虛繼承及繼承的內存布局


轉自:http://blog.csdn.net/xsh_123321/article/details/5956289

1.為什么需要虛繼承

如下圖所示如果訪問Der::Fun or Der::m_nValue就會帶來二義性,無法確定是調用Base1的還是Base2的,所以為了解決多重繼承情況下成員訪問的二義性,引入了虛繼承機制。
一般繼承:
一般繼承

虛繼承:
虛繼承

2.虛繼承實現

在虛繼承下,Der通過共享虛基類SuperBase來避免二義性,在Base1,Base2中分別保存虛基類指針,Der繼承Base1,Base2,包含Base1, Base2的虛基類指針,並指向同一塊內存區,這樣Der便可以間接存取虛基類的成員,如下圖所示:

3.不同編譯器實現方式

不同編譯器對間接存取的方法不同,以下以GCC和VC為例,均采用以下代碼進行實驗:

class SuperBase
{
public:
    int m_nValue;
    void Fun(){}
    virtual ~SuperBase(){}
};
class Base1:  virtual public SuperBase
{
public:
virtual ~ Base1(){}
};
class Base2:  virtual public SuperBase
{
public:
virtual ~ Base2(){}
};
class Der:public Base1, public Base2
{
public:
virtual ~ Der(){}
};

1) GCC中結果為8, 12, 12, 16

解析:sizeof(SuperBase) = sizeof(int) + 虛函數表指針

sizeof(Base1) = sizeof(Base2) = sizeof(int) + 虛函數指針 + 虛基類指針

sizeof(Der) = sizeof(int) + Base1中虛基類指針 + Base2虛基類指針 + 虛函數指針

GCC共享虛函數表指針,也就是說父類如果已經有虛函數表指針,那么子類中共享父類的虛函數表指針空間,不在占用額外的空間,這一點與VC不同,VC在虛繼承情況下,不共享父類虛函數表指針,詳見如下。

2)VC中結果為:8, 16, 16, 24

解析:sizeof(SuperBase) = sizeof(int) + 虛函數表指針

sizeof(Base1) = sizeof(Base2) = sizeof(int) + SuperBase虛函數指針 + 虛基類指針 + 自身虛函數指針

sizeof(Der) = sizeof(int) + Base1中虛基類指針 + Base2中虛基類指針 + Base1虛函數指針 + Base2虛函數指針 + 自身虛函數指針

如果去掉虛繼承,結果將和GCC結果一樣,A,B,C都是8,D為16,原因就是VC的編譯器對於非虛繼承,父類和子類是共享虛函數表指針的。

 

繼承中的內存布局

1. 虛函數指針(vptr)放最前,之后放變量。
2. 多個父類排着放,再放子類
3. 子類的覆蓋的虛函數將所有祖先的同名虛函數都覆蓋。
4. 子類其它的虛函數指針放在第一個父類的虛函數表里。
5. 虛擬繼承的情況只需要在鑽石繼承中有必要使用(避免二義性),子類中最先的祖先放最后。

多說不如舉例,看下面轉的文章。

本文章轉自:http://blog.csdn.net/randyjiawenjie/article/details/6693337

分為四種情況:
1.單繼承

2.多繼承(不含鑽石繼承)

3.非虛繼承的鑽石繼承

4.虛繼承的鑽石繼承

注:下面所有類中的函數都是虛函數。

1.單繼承

單繼承體系如下:

GrandChild對象的內存布局:

可見以下幾個方面:

1)虛函數表在最前面的位置。

2)成員變量根據其繼承和聲明順序依次放在后面。

3)在單一的繼承中,被overwrite的虛函數在虛函數表中得到了更新。

2.多繼承

多繼承的體系如下:

Derive對象的內存布局如下:

我們可以看到:

1) 每個父類都有自己的虛表。

2) 子類的成員函數被放到了第一個父類的表中。

3) 內存布局中,其父類布局依次按聲明順序排列。

4) 每個父類的虛表中的f()函數都被overwrite成了子類的f()。這樣做就是為了解決不同的父類類型的指針指向同一個子類實例,而能夠調用到實際的函數。

出現鑽石繼承的虛繼承的時候,虛基類在子類中只有一份。

出現鑽石繼承的非虛繼承的時候,虛基類在每個子類中都有一份。

3.非虛繼承的鑽石繼承

繼承體系如下:

D的內存布局如下:

紅色的部分就是重復的部分,就會造成二義性

4.虛繼承的鑽石繼承

(虛繼承就是解決鑽石繼承問題的,如果不存在鑽石繼承,就不用虛繼承)

繼承體系如下:(紅色專門標准虛繼承)


D的內存布局如下:

可以看出,少了重合的部分。但是,代價是增加了一個虛函數指針。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM