C++虛繼承內存對象模型探討
最近看了下Inside C++裏面講的對虛繼承層次的對象的內存佈局,發現在不同編譯器實現有所區別。因此,自己動手探索了一下。結果如下:
首先,說說GCC的編譯器.
它實現比較簡單,不管是否虛繼承,GCC都是將虛表指針在整個繼承關係中共享的,不共享的是指向虛基類的指針。
class A {
int a;
virtual ~A(){}
};
class B:virtual public A{
virtual ~B(){}
virtual void myfunB(){}
};
class C:virtual public A{
virtual ~C(){}
virtual void myfunC(){}
};
class D:public B,public C{
virtual ~D(){}
virtual void myfunD(){}
};
以上代碼中 sizeof(A)=8,sizeof(B)=12,sizeof(C)=12,sizeof(D)=16.
解釋:A中int+虛表指針。B,C中由於是虛繼承因此大小爲A+指向虛基類的指針,B,C雖然加入了自己的虛函數,但是虛表指針是和基類共享的,因此不會有自己的虛表指針。D由於B,C都是虛繼承,因此D只包含一個A的副本,於是D大小就等於A+B中的指向虛基類的指針+C中的指向虛基類的指針。
如果B,C不是虛繼承,而是普通繼承的話,那麼A,B,C的大小都是8(沒有指向虛基類的指針了),而D由於不是虛繼承,因此包含兩個A副本,大小爲16. 注意此時雖然D的大小和虛繼承一樣,但是內存佈局卻不同。
然後,來看看VC的編譯器
vc對虛表指針的處理比GCC複雜,它根據是否爲虛繼承來判斷是否在繼承關係中共享虛表指針,而對指向虛基類的指針和GCC一樣是不共享,當然也不可能共享。
代碼同上。
運行結果將會是sizeof(A)=8,sizeof(B)=16,sizeof(C)=16,sizeof(D)=24.
解釋:A中依然是int+虛表指針。B,C中由於是虛繼承因此虛表指針不共享,由於B,C加入了自己的虛函數,所以B,C分別自己維護一個虛表指針,它指向自己的虛函數。(注意:只有子類有新的虛函數時,編譯器纔會在子類中添加虛表指針)因此B,C大小爲A+自己的虛表指針+指向虛基類的指針。D由於B,C都是虛繼承,因此D只包含一個A的副本,同時D是從B,C普通繼承的,而不是虛繼承的,因此沒有自己的虛表指針。於是D大小就等於A+B的虛表指針+C的虛表指針+B中的指向虛基類的指針+C中的指向虛基類的指針。
同樣,如果去掉虛繼承,結果將和GCC結果一樣,A,B,C都是8,D爲16,原因就是VC的編譯器對於非虛繼承,父類和子類是共享虛表指針的。