虛繼承及繼承的記憶體布局

2021-08-19 19:15:35 字數 2262 閱讀 7072

1.為什麼需要虛繼承

如下圖所示如果訪問der::fun or der::m_nvalue就會帶來二義性,無法確定是呼叫base1的還是base2的,所以為了解決多重繼承情況下成員訪問的二義性,引入了虛繼承機制。

一般繼承:

虛繼承:

2.虛繼承實現

在虛繼承下,der通過共享虛基類superbase來避免二義性,在base1,base2中分別儲存虛基類指標,der繼承base1,base2,包含base1, base2的虛基類指標,並指向同一塊記憶體區,這樣der便可以間接訪問虛基類的成員,如下圖所示:

class superbase

virtual ~superbase() {}

};class base1 : virtual public superbase

};class base2 : virtual public superbase

};class der :public base1, public base2

};int main()

{printf("sizeof(superbase)= %d\n",sizeof(superbase));

// sizeof(int)+8個位元組的虛表指標。= 12  64位,指標8個位元組,保證是8個位元組的倍數,16

printf("sizeof(base1)= %d\n", sizeof(base1));      

// sizeof(int)+8個位元組的虛表指標。+8個位元組的虛擬base指標= 20 指標8個位元組,保證是8個位元組的倍數,24

printf("sizeof(base2)= %d\n", sizeof(base2));

// sizeof(int)+8個位元組的虛表指標。+8個位元組的虛擬base指標= 20 指標8個位元組,保證是8個位元組的倍數,24

printf("sizeof(der)= %d\n", sizeof(der));

// sizeof(int)+8個位元組的虛表指標。+8個位元組的虛擬base指標 + 8個位元組的虛擬base指標= 28

// 指標8個位元組,保證是8個位元組的倍數,32

繼承中的記憶體布局

1. 虛函式指標(vptr)放最前,之後放變數。

2. 多個父類排著放,再放子類

3. 子類的覆蓋的虛函式將所有祖先的同名虛函式都覆蓋。

4. 子類其它的虛函式指標放在第乙個父類的虛函式表裡。

5. 虛擬繼承的情況只需要在鑽石繼承中有必要使用(避免二義性),子類中最先的祖先放最後。

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

本文章**:

分為四種情況:

1.單繼承

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

3.非虛繼承的鑽石繼承

4.虛繼承的鑽石繼承

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

1.單繼承

單繼承體系如下:

grandchild物件的記憶體布局:

可見以下幾個方面:

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

2)成員變數根據其繼承和宣告順序依次放在後面。

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

2.多繼承

多繼承的體系如下:

derive物件的記憶體布局如下:

我們可以看到:

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

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

3) 記憶體布局中,其父類布局依次按宣告順序排列。

4) 每個父類的虛表中的f()函式都被overwrite成了子類的f()。這樣做就是為了解決不同的父類型別的指標指向同乙個子類例項,而能夠呼叫到實際的函式。

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

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

3.非虛繼承的鑽石繼承

繼承體系如下:

d的記憶體布局如下:

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

4.虛繼承的鑽石繼承

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

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

d的記憶體布局如下:

可以看出,少了重合的部分。但是,代價是增加了乙個虛函式指標。

虛繼承之單繼承的記憶體布局

c 2.0以後全面支援虛函式與虛繼承,這兩個特性的引入為c 增強了不少功能,也引入了不少煩惱。虛函式與虛繼承有哪些特性,今天就不記錄了,如果能搞了解一下編譯器是如何實現虛函式和虛繼承,它們在類的記憶體空間中又是如何布局的,卻可以對c 的了解深入不少。這段時間花了一些時間了解這些玩意,搞得偶都,不過總...

虛繼承之單繼承的記憶體布局

c 2.0以後全面支援虛函式與虛繼承,這兩個特性的引入為c 增強了不少功能,也引入了不少煩惱。虛函式與虛繼承有哪些特性,今天就不記錄了,如果能搞了解一下編譯器是如何實現虛函式和虛繼承,它們在類的記憶體空間中又是如何布局的,卻可以對c 的了解深入不少。這段時間花了一些時間了解這些玩意,搞得偶都 先看一...

直接繼承和虛繼承的記憶體布局

子類物件的記憶體布局 虛表指標 父類成員變數 子類成員變數 虛函式表的布局 父類的虛函式位址 按宣告順序 子類自定義的虛函式的位址 按宣告順序 子類物件的記憶體布局 虛表指標 父類成員變數 子類成員變數 虛函式表的布局 子類已覆蓋的虛函式的位址 父類中未被覆蓋的虛函式的位址 子類自定義的虛函式的位址...