先看一個空的類占多少空間?
- class Base
- {
- public:
- Base();
- ~Base();
- };
注意到我這里顯示聲明了構造跟析構,但是sizeof(Base)的結果是1.
因為一個空類也要實例化,所謂類的實例化就是在內存中分配一塊地址,每個實例在內存中都有獨一無二的地址。同樣空類也會被實例化,所以編譯器會給空類隱含的添加一個字節,這樣空類實例化之后就有了獨一無二的地址了。所以空類的sizeof為1。
而析構函數,跟構造函數這些成員函數,是跟sizeof無關的,也不難理解因為我們的sizeof是針對實例,而普通成員函數,是針對類體的,一個類的成員函數,多個實例也共用相同的函數指針,所以自然不能歸為實例的大小,這在我的另一篇博文有提到。
接着看下面一段代碼
- class Base
- {
- public:
- Base();
- virtual ~Base(); //每個實例都有虛函數表
- void set_num(int num) //普通成員函數,為各實例公有,不歸入sizeof統計
- {
- a=num;
- }
- private:
- int a; //占4字節
- char *p; //4字節指針
- };
- class Derive:public Base
- {
- public:
- Derive():Base(){};
- ~Derive(){};
- private:
- static int st; //非實例獨占
- int d; //占4字節
- char *p; //4字節指針
- };
- int main()
- {
- cout<<sizeof(Base)<<endl;
- cout<<sizeof(Derive)<<endl;
- return 0;
- }
結果自然是
12
20
Base類里的int a;char *p;占8個字節。
而虛析構函數virtual ~Base();的指針占4子字節。
其他成員函數不歸入sizeof統計。
Derive類首先要具有Base類的部分,也就是占12字節。
int d;char *p;占8字節
static int st;不歸入sizeof統計
所以一共是20字節。
在考慮在Derive里加一個成員char c;
- class Derive:public Base
- {
- public:
- Derive():Base(){};
- ~Derive(){};
- private:
- static int st;
- int d;
- char *p;
- char c;
- };
這個時候,結果就變成了
12
24
一個char c;增加了4字節,說明類的大小也遵守類似class字節對齊,的補齊規則。
具體的可以看我那篇《5分鍾搞定字節對齊》
至此,我們可以歸納以下幾個原則:
1.類的大小為類的非靜態成員數據的類型大小之和,也就是說靜態成員數據不作考慮。
2.普通成員函數與sizeof無關。
3.虛函數由於要維護在虛函數表,所以要占據一個指針大小,也就是4字節。
4.類的總大小也遵守類似class字節對齊的,調整規則。