最近看了下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的編譯器對於非虛繼承,父類和子類是共享虛表指針的。ide