http://blog.csdn.net/vangoals/article/details/4264512
關於類的大小sizeof()的計算
首先,來看看一個只有構造函數和析構函數的空類:
- #include <iostream>
- using namespace std;
- class Base
- {
- public:
- Base();
- ~Base();
- };
- int main(int argc, char *argv[])
- {
- cout << sizeof(Base) << endl;
- }
輸出結果爲:1
因爲一個空類也要實例化,所謂類的實例化就是在內存中分配一塊地址,每個實例在內存中都有獨一無二的地址。同樣空類也會被實例化,所以編譯器會給空類隱含的添加一個字節,這樣空類實例化之後就有了獨一無二的地址了。所以空類的sizeof爲1。 而析構函數,跟構造函數這些成員函數,是跟sizeof無關的,也不難理解因爲我們的sizeof是針對實例,而普通成員函數,是針對類體的,一個類的成員函數,多個實例也共用相同的函數指針,所以自然不能歸爲實例的大小。
如果給這個類添加成員變量,最後輸出的大小就是這些成員變量的大小之和(這裏涉及到一個成員對齊問題,不再敘述了)。
接下來再來看一個有繼承的例子:
- #include <iostream>
- using namespace std;
- class Base
- {
- public:
- Base();
- ~Base();
- void set_num(int num) //普通成員函數
- {
- a=num;
- }
- private:
- int a; //佔4字節
- char *p; //4字節指針
- };
- class Derive:public Base
- {
- public:
- Derive():Base(){};
- ~Derive(){};
- private:
- static int st; //非實例獨佔
- int d; //佔4字節
- };
- int main(int argc, char *argv[])
- {
- cout<<sizeof(Base)<<endl;
- cout<<sizeof(Derive)<<endl;
- return 0;
- }
輸出結果爲:8 12
結果很顯然, Base 類按4字節對齊,所以是8個字節,Derive 類中不但繼承了Base 類的兩個成員變量,還多了兩個成員變量,但大小卻只有12字節,可以得出:靜態變量在計算時是不做考慮的。
上面的例子中都沒有涉及到虛函數,下面看個有虛函數的例子:
- #include <iostream>
- using namespace std;
- class Base
- {
- public:
- Base() {}
- virtual ~Base() {}
- };
- int main(int argc, char *argv[])
- {
- cout << sizeof(Base) << endl;
- return 0;
- }
輸出結果爲:4
和第一個程序相比,這個類中,析構函數變成了虛函數,類的大小也變成了4字節,這是因爲有了虛函數,編譯器就會爲類創建一個虛函數表(vtable),並創建一個指針(vptr)指向這個虛函數表。所以類大小變爲4字節。如果在 Base 類中再添加新的虛函數,該類的大小還是不會變,因爲指向虛函數的指針是放在虛函數表中的,指向虛函數表的指針不會變。
如果在這個類中添加數據成員,就會在4字節的基礎上對象大小。
下面再來看看虛函數的繼承問題:
- #include <iostream>
- using namespace std;
- class Base
- {
- public:
- Base();
- virtual ~Base();
- void set_num(int num) //普通成員函數
- {
- a=num;
- }
- private:
- int a; //佔4字節
- char *p; //4字節指針
- };
- class Derive:public Base
- {
- public:
- Derive():Base(){};
- ~Derive(){};
- virtual void foo() { }
- private:
- static int st; //非實例獨佔
- int d; //佔4字節
- };
- int main(int argc, char *argv[])
- {
- cout<<sizeof(Base)<<endl;
- cout<<sizeof(Derive)<<endl;
- return 0;
- }
輸出結果爲:12 16
Base類的大小爲12字節很顯然,Derive 類中,雖然有一個虛函數 foo ,但是因爲它是從Base 類繼承的,所以也繼承了其虛函數表,並沒有創新新的虛函數表,只是在繼承下來的表中添加了一項,所以大小爲16字節。
再來看看一個虛繼承的例子:
- #include <iostream>
- using namespace std;
- class Base
- {
- public:
- Base();
- virtual ~Base();
- void set_num(int num) //普通成員函數
- {
- a=num;
- }
- private:
- int a; //佔4字節
- char *p; //4字節指針
- };
- class Derive:virtual public Base
- {
- public:
- Derive():Base(){};
- ~Derive(){};
- virtual void foo() { }
- private:
- static int st; //非實例獨佔
- int d; //佔4字節
- };
- int main(int argc, char *argv[])
- {
- cout<<sizeof(Base)<<endl;
- cout<<sizeof(Derive)<<endl;
- return 0;
- }
輸出結果爲:12 20
這裏由於虛繼承而引入了一個間接的指針(vbc),該指針是指向虛函數表的一個slot,表中存放着該slot中存放虛基類子對象的偏移量的負值。所以大小比之前多了4字節。就算同時虛繼承自兩個類,也只會有一個這樣的間接指針,也就是大小也只多4字節。
說到這裏,關於類對象大小問題的計算應該差不多了。
關於string的大小sizeof()的計算。
string 內部的實現是保存一個指針,sizeof(string)等同與sizeof(char *),所以sizeof(string)的大小如果是32位平臺的話是4.