昨天去了一家學長的公司,談了談我的疑惑,然後做了乙份題。有一些收穫,想跟大家分享一下。主要是c++物件的sizeof問題。
先上**
#include "stdafx.h"
#include class a {};
class b ;
class c ;
class d ;
int _num;
};class e : public d ;
class f : virtual public a {};
class g : virtual public f {};
class h : virtual public a ;
class i : virtual public h {};
int main(int argc, char* argv)
請問結果是怎樣的呢?
這裡我在a和c的判斷上出了問題,我將a和c都是寫了4,但是結果都是1。下面是執行結果截圖:
查了資料後發現,原來a之所以是1不是0的原因是因為c++中的一條規定:每個物件的位址都應該是獨一無二的。這句話怎麼理解呢,比如你a a[10],就有10個a型別的物件了,如果sizeof(a) = 0的話,那這10個物件的位址不就都重合了麼。之所以不為4呢,也是考慮到空物件既然沒有東西,就盡量少占用資源,所以就只給它分配了乙個位元組。
至於c,static變數是所有該型別的物件通用的,所以c_num是存在靜態變數區的,在sizeof(c)的計算時,並不會把c_num的大小計算進去,所以c跟a的sizeof其實是等價的。
b因為int佔4個位元組,所以size為4很好理解。d是有乙個虛函式指標,乙個int值,指標4個位元組int4個位元組,一共為8也很好理解。哦對了,虛函式指標是如果你的類存在虛函式,編譯器就會幫你構造乙個表,這個表裡存的都是虛函式,而類內就會多出來乙個隱藏的指標,這個指標指向虛函式表的表頭。為了理解,我舉個例子。
class fooofvirtual ;
這麼多虛函式,fooofvirtual的size依然為8。這樣一來就理解了吧?
那麼e為什麼為12呢,這涉及到位元組對齊的問題。位元組對齊就是說,如果不按照適合其平台要求對 資料存放進行對齊,會在訪問效率上帶來損失。比如有些平台每次讀都是從偶位址開始,如果乙個int型(假設為32位系統)如果存放在偶位址開始的地方,那 麼乙個讀週期就可以讀出這32bit,而如果存放在奇位址開始的地方,就需要2個讀週期,並對兩次讀出的結果的高低位元組進行拼湊才能得到該32bit資料。更詳細的可以去網上查閱資料理解。
我們來分析一下為何e為12,首先e繼承自d,d為8,char為1位元組。但是別忘了位元組對齊,預設情況是讀取變數中size最大的成員的位元組數來對齊的,也就是int的4(當然虛函式指標也為4).這麼一來,char雖然是1個位元組的變數,但是會自動後面補上 00 00 00,也就成了4個位元組,共12個位元組。
針對上面,我給出乙個例子:
class format1 ;
class format2 ;
class format3 ;
這三個類分別size為多少呢?結果分別是1 2 4。為什麼呢?第乙個和第二個char型是size最大的,所以有效對齊值為1,2。第三個是short最大,所以有效對齊值為2,,2*2=4。還有,如果你想手動設定對齊值,那麼看下面乙個例子
class format1 ;
#pragma pack(push)
#pragma pack(1)
class format2 ;
#pragma pack(pop)
1和2的size分別為8 5。這是因為在format2中,通過語句#pragma pack(1)將對齊值統一設定為了1.對4位元組長度的int型變數來說,4%1 = 0;符合,char 有 1%1 =0符合。故不進行對齊操作。所以size為5。至於語句
#pragma pack(push)
#pragma pack(pop)
1.資料型別自身的對齊值:
對於char型資料,其自身對齊值為1,對於short型為2,對於int,float型別,其自身對齊值為4,對於double型,其自身對齊值為8,單位位元組。
2.結構體或者類的自身對齊值:其成員中自身對齊值最大的那個值。
3.指定對齊值:#pragma pack (value)時的指定對齊值value。
4.資料成員、結構體和類的有效對齊值:自身對齊值和指定對齊值中小的那個值。
好啦,繼續回到我們的主題,現在是f,g,h,i的解釋環節。可以這麼理解,每虛繼承乙個類,當前類的大小有如下公式:
原來本身大小(為空時算0) + 4(指向虛繼承的類的乙個指標) + 虛繼承的類的大小(為空時算0) = 當前大小。
這樣一來,是不是就能了解上面的size了?但是,但是!!來看乙個例子:
#include "stdafx.h"
#include class a {};
class b : virtual public a ;
class c : virtual public a ;
class d : virtual public b, virtual public c {};
int main(int argc, char* argv)
這裡是入口
也就是說a作為乙個又被b又被c虛繼承的基類,它在d中只有乙個指標,也就是只占用一次4位元組,這樣一來,是不是公式又正確了呢。
另外要注意的是,虛繼承跟繼承的差別很大的哦,具體可以看這篇博文:這裡是入口
好了,這次的c++物件模型的sizeof問題就到這裡了,以小見大,這些細枝末節其實才是最能體現乙個人的功力的地方。希望各位同學共勉。
c C 物件模型和this指標
在c 中,類內的成員變數和成員函式分開儲存 只有非靜態成員變數才屬於類的物件上 1 空物件的大小 空物件占用記憶體空間為 1 c 編譯器會給每個空物件也分配乙個位元組空間,是為了區分空物件佔記憶體的位置 每任空物件也應該有乙個獨一 無二的記憶體位址 include using namespace s...
C C 中sizeof的運用
通過實踐將個人對sizeof的理解寫到這裡,還望大家的指點 以下是我的實踐 include class a class b class c class d virtual public b class e public c class f virtual public b class g publi...
C C 關於sizeof 的規律
1.每個變數在記憶體中的位置一定是其位元組大小的整數倍 2.結構體整體位元組大小一定是該結構體中最大的位元組變數的整數倍 3.不能存放變數的位元組位置時自動填充該位置 4.結構體整體位元組大小不是該結構體中最大的位元組變數的整數倍時往後填充使其成為整數倍 先來幾個例子 1 include using...