1. 程式人生 > 其它 >C++ 菱形繼承與虛擬繼承

C++ 菱形繼承與虛擬繼承

文章目錄

1. 什麼是菱形繼承?

單繼承:一個子類只有一個直接父類時稱這個繼承關係為單繼承
多繼承:一個子類有兩個或以上直接父類時稱這個繼承關係為多繼承
菱形繼承:菱形繼承是C++ 多繼承的一種表現形式

用一張簡單的圖就可以說明什麼是菱形繼承

圖一

2. 菱形繼承的問題是什麼?

繼承最簡單的理解就是子類將父類中的成員拷貝了一份。我們用最簡單的四個類A,B,C,D有且僅有一個成員變數分別是 m_a = 1, m_b = 2, m_c = 3, m_d = 4。B 和 C都繼承了 A 類,所以 B 類和 C 類裡分別有繼承A類的一份 m_a,而D類又同時繼承了B和C,這樣一來D類裡就有了兩份 m_a。使得 m_a 在四個類中都存在導致資料冗餘;而當D類物件訪問類中成員 m_a 時,由於有兩份 m_a ,最終導致出現二義性。總結出來菱形繼承的問題就是會導致資料冗餘和二義性。

3.如何解決菱形繼承的問題

解決方法:讓 B 虛擬繼承 A,C 虛擬繼承 A。A 也就被稱為虛基類。虛擬繼承會讓父類 A 的成員在最終子類 D 中只有一份。需要注意的是:虛擬繼承不要在其他地方去使用。基本用不到。

例項程式碼:

class A
{
public:
	int m_a = 1;
};
class B : virtual public A
{
public:
	int m_b = 2;
};
class C : virtual public A
{
public:
	int m_c = 3;
};
class D : public B, public C
{
public:
	int
m_d = 4; };

4.虛擬繼承解決菱形繼承問題的原理

我們可以利用編譯器的記憶體視窗來觀察虛擬繼承解決資料冗餘和二義性的原理。還是利用上面的簡單程式碼來說明問題。

在這裡插入圖片描述
這是沒有使用虛擬繼承的記憶體視窗,可以看出有資料 m_a = 1冗餘,並且在D類物件訪問 m_a 時,計算機不知道是訪問 B 裡的 m_a 還是 C 裡的 m_a ,這樣就造成了二義性。

在這裡插入圖片描述
這是使用了虛擬繼承的記憶體視窗,這裡可以分析出D物件中將繼承的 m_a 放到的了物件組成的最下面,這個 m_a 同時屬於B和C。B中的地址 0x0020e1b0 和C 中的地址 0x0020dbbc 其實是兩個虛基表指標,分別指向兩張虛基表,虛基表中存放有 m_a 的偏移量。計算機可以通過偏移量找到 m_a

。這就解決了菱形繼承的資料冗餘和二義性的問題。

利用虛基表和偏移量找到 m_a 的過程。
在這裡插入圖片描述
B裡存放的虛基表指標,指向的虛基表裡存放的是如圖(14)16 即(20)10的偏移量,在虛擬繼承的記憶體窗口裡從B開始數20個位元組,剛好訪問到 m_a = 1。
在這裡插入圖片描述
C裡存放的虛基表指標,指向的虛基表裡存放的是如圖(0c)16 即(12)10的偏移量,在虛擬繼承的記憶體窗裡從C開始數12個位元組,也剛好訪問到 m_a = 1。