class X{};
class Y:public virtual X{};
class Z:public virtual X{};
class A:public Y,public Z{};
sizeof X:1 Y:4 Z:4 A:8
類的實例化,所謂類的實例化就是在內存中分配一塊地址,每個實例在內存中都有獨一無二的地址。同樣空類也會被實例化,所以編譯器會給空類隱含的添加一個字節,這樣空類實例化之後就有了獨一無二的地址了。所以空類的sizeof爲1。
Y和Z的大小受到三個因素的影響:
1、語言本身所造成的額外負擔(overhead): 當語言支持virtual base classes時,就會導致一些額外負擔。在derived class中,這個額外負擔反映在某種形式的指針身上,它或者指向virtual base class subobject,或者指向一個相關表格:表格中存放的若不是virtual base class subobject的地址,就是其偏移量(offset, 這正是VC++的做法)。
2、編譯器對於特殊情況所提供的優化處理:Virtual base class X subobject的1 bytes大小也出現在Class Y和Z身上。某些編譯器會對empty virtual base class 提供特殊支持。
3、Alignment的限制:Class Y和 Z的大小截至目前爲5 bytes。在大部分機器上,羣聚的結構體大小會受到alignment的限制,使它們能夠更有效率地在內存中被存取。在32位機上,alignment是4bytes,所以class Y和Z必須填補3 bytes。最終得到的結果就是8 bytes。
現在有些編譯器提供“空基類優化”(empty base class optimization),一個empty virtual base class被視爲derived class object最開頭的一部分,也就是說它並沒有花費任何的額外空間。這就節省了上述第2點的1bytes,也就不再需要第三點所說的3bytes的填補。
class Onefunc{
public:
void go(void);
};
void Onefunc::go()
{
cout<<"HAHA"<<endl;
}
cout<<"Onefunc:"<<sizeof(Onefunc)<<endl; //結果:Onefunc:1
類的大小與(非虛)函數無關,其大小決定於:成員變量,vptr(指向VTable的virtual pointer), Vbptr(virtual base table pointer)。在類Onefunc裏什麼都沒有,故大小與空類大小相同。
【轉】 C++類的大小——sizeof()
先看這麼個問題——已知:
{
int a;
char *p;
};
那麼運行cout<<"sizeof(CBase)="<<sizeof(CBase)<<endl;之後輸出什麼?
這個應該很簡單,兩個成員變量所佔的大小有嘛——8。可由時候人就是愛犯這個錯誤:這麼簡單的問題人家會問你?再想想……好像C++類裏面有個什麼函數指針,也應該佔字節吧!?什麼指針來着?忘了(還是水平低不紮實)!流汗中……算了姑且認爲是構造函數和析構函數吧。一人一個加上剛纔那8個16個。好笑嗎?這是我犯的錯誤!!!到底C++類的sizeof是多少呢?沒有所謂的函數指針問題嗎?不甘心,編個例子看看:
第一步:給丫來個空的(不好意思上火粗魯了)
{
};
運行cout<<"sizeof(CBase)="<<sizeof(CBase)<<endl;
sizeof(CBase)=1;
爲什麼空的什麼都沒有是1呢?查資料……查啊查……OK這裏了:先了解一個概念:類的實例化,所謂類的實例化就是在內存中分配一塊地址,每個實例在內存中都有獨一無二的地址。同樣空類也會被實例化(別拿豆包不當乾糧,空類也是類啊),所以編譯器會給空類隱含的添加一個字節,這樣空類實例化之後就有了獨一無二的地址了。所以空類的sizeof爲1。繼續下一步:
第二步:
還是最初的那個類,運行結果:sizeof(CBase)=8
沒什麼說的,兩個內部變量的大小。難道我記錯了沒有什麼指針問題的存在?再試試(早這麼有求知慾也不會丟人了,這回來勁了)
第三步:添個虛函數
{
public:
CBase(void);
virtual ~CBase(void);
private:
int a;
char *p;
};
再運行:sizeof(CBase)=12
嗨!問題出來了!!跟虛函數有關。爲什麼呢?查資料ing……
有了:“C++ 類中有虛函數的時候有一個指向虛函數的指針(vptr),在32位系統分配指針大小爲4字節”噢原來如此害死我了。那麼繼承類呢?
第四步:
基類就是上面的了不寫了
public CBase
{
public:
CChild(void);
~CChild(void);
private:
int b;
};
運行:cout<<"sizeof(CChild)="<<sizeof(CChild)<<endl;
輸出:sizeof(CChild)=16;
可見子類的大小是本身成員變量的大小加上子類的大小。
有空再補一下關於虛函數指針的知識吧。