一個空類class A{};的大小為什么是1,因為如果不是1,當定義這個類的對象數組時候A objects[5]; objects[0]和objects[1]就在同一個地址處,就無法區分。
單繼承
#include<iostream> using namespace std; class A { public: virtual void aa(){} private: char k[3]; }; class B: public A { public: virtual void bb(){} }; int main() { cout<<"A's size is "<<sizeof(A)<<endl; cout<<"B's size is "<<sizeof(B)<<endl; return 0; }
vs和gcc下
執行結果:A's size is 8
B's size is 8
說明:有虛函數的類有個virtual table(虛函數表),里面包含了類的所有虛函數,類中有個virtual table pointers,通常成為vptr指向這個virtual table,占用4個字節的大小。成員類B public繼承於A,類B的虛函數表里實際上有兩個虛函數A::aa()和B::bb(),類B的大小等於char k[3]的大小加上一個指向虛函數表指針vptr的大小,考慮內存對齊為8。
#include<iostream> using namespace std; class A { public: virtual void aa(){} private: char k[3]; }; class B: public A { public: //virtual void bb(){} }; int main() { cout<<"A's size is "<<sizeof(A)<<endl; cout<<"B's size is "<<sizeof(B)<<endl; return 0; }
vs和gcc下
執行結果:A's size is 8
B's size is 8
說明:類B看上去沒有虛函數,但實際上它有,只是沒有重寫,因為public繼承,所以有從A繼承過來的虛函數A::aa(),實際上類A和類B的虛函數表里的函數都是A::aa()。
#include<iostream> using namespace std; class A { public: virtual void aa(){} virtual void aa2(){} private: char k[3]; }; class B: public A { public: virtual void bb(){} virtual void bb2(){} }; int main() { cout<<"A's size is "<<sizeof(A)<<endl; cout<<"B's size is "<<sizeof(B)<<endl; return 0; }
vs和gcc下
執行結果:A's size is 8
B's size is 8
說明:一個類里若有虛函數,無論有多少個虛函數都只有一個指向虛表的指針,虛表中的每一個表項保存着一個虛函數的入口地址。當調用虛函數時,先找到虛表中它對應的表項,找到入口地址再執行。對於直接單繼承,無論類B中有無虛函數,由於它繼承了類A,且類A里含有虛函數,因此如果類B有虛函數,那么它和類A的是在同一個屬於類B的虛表里,這張虛表的虛函數為A::aa()、A::aa2()、B::bb()、B::bb2()。注意:類A里的私有成員在類B里仍占有內存。
多繼承
#include<iostream> using namespace std; class A { public: virtual void aa(){} virtual void aa2(){} private: char k[3]; }; class B { public: virtual void bb(){} virtual void bb2(){} }; class C: public A,public B { public: virtual void aa(){} //重寫了A的aa() virtual void cc(){} }; int main() { cout<<"A's size is "<<sizeof(A)<<endl; cout<<"B's size is "<<sizeof(B)<<endl; cout<<"C's size is "<<sizeof(C)<<endl; return 0; }
vs和gcc下
執行結果:A's size is 8
B's size is 4
B's size is 12
說明:類A和B的大小就不解釋了,參照上面。類C多重繼承於A和B(有虛函數覆蓋),那么類C的大小是多少?先看成員變量,有一個繼承A的char k[3]。再看虛函數,類C的中虛函數是怎么分布的?先有一個虛函數表,里面有繼承於類A的虛函數和C自己的虛函數(C::aa(), A::aa2(), C::cc()),如果C沒有重寫aa(),那么第一個虛函數就是A::aa(),接着有第二張虛函數表是繼承包含類B的虛函數B::bb()、B::bb2()(類C沒有重寫B的虛函數)。總的大小就是2張虛表的大小(也即兩個虛函數指針的大小)8字節加上3字節的k[3],考慮內存對齊,就是12字節。
虛繼承
#include<iostream> using namespace std; class A { public: virtual void aa(){} private: char k[3]; }; class B: virtual public A { public: //virtual void bb(){} }; int main() { cout<<"A's size is "<<sizeof(A)<<endl; cout<<"B's size is "<<sizeof(B)<<endl; return 0; }
vs和gcc下
執行結果:A's size is 8
B's size is 12
說明:類B里包含,繼承的char k[3],繼承的虛函數,類B的虛函數表里有A::aa(),因為是虛繼承,還有一個指向父類的指針,該指針為指向虛基類的指針(Pointer to virtual base class)。考慮內存對齊,總大小為12。
#include<iostream> using namespace std; class A { public: virtual void aa(){} private: char k[3]; }; class B: public virtual A { public: virtual void bb(){} }; int main() { cout<<"A's size is "<<sizeof(A)<<endl; cout<<"B's size is "<<sizeof(B)<<endl; return 0; }
VS執行結果:A's size is 8
B's size is 16
gcc執行結果:A's size is 8
B's size is 12
說明:對於虛繼承,類B虛繼承類A時,首先要通過加入一個指針來指向父類A,該指針被稱為虛基類指針。然后包含從父類繼承過來的3個char,再加上一個虛函數指針。考慮內存對齊,在gcc下結果是4+4+4=12。在VS下,結果是16,why?這一題和上一題區別只是在類B中添加了一個虛函數,但是兩個題目中類B都有虛函數表。在VS下調試查看匯編代碼,發現多出來的4字節什么也沒有。
關於C++虛函數,可以看《C++虛函數表解析》:http://blog.csdn.net/haoel/article/details/1948051