菱形繼承問題以及虛擬繼承探究
阿新 • • 發佈:2018-12-11
在前邊的部落格中我提到過菱形繼承的問題,也給出了幾種解決菱形繼承的方法
但是給的方法沒有說明原因,這篇部落格將會從記憶體儲存模型角度,以及虛繼承為什麼可以使解決菱形繼承的問題進行闡述與證明。
所謂菱形繼承就是指類B,類C同時繼承A,且D同時繼承B,C,在A具有成員函式的情況下,在D類例項化出來的物件中對A的成員函式進行直接呼叫會發生二義性的問題,也就是編譯器不知道是尋找B繼承的成員函式還是A繼承的成員函式。
但是在B,C繼承A的時候,加上虛繼承則不會發生錯誤
但是為什麼虛繼承會使得這種問題得以解決呢?
原因是虛繼承其實改變了傳統的類繼承的空間結構模型,可以在記憶體顯示視窗看到
為了使得記憶體易於找到,在A中放入幾個值,則有以下程式碼:
#include <iostream> using namespace std; class A { public: A() :a(1) {} void Print(void) { cout << "hello" << endl; } int a; }; class B:virtual public A{ public: B() :b(2) {} int b; }; class C:virtual public A{ public: C() :c(3) {} int c; }; class D:public B, public C{ public: D() :d(4) {} int d; }; int main() { D d; d.Print(); return 0; }
執行起來記憶體分佈結構為:
顯而易見的結果是:
最底部為A的成員,有A的獨立資料,在A之上存放D的獨有資料,D之上存放著C的獨有資料的同時有一個類似地址的十六進位制值,同時B也有一個類似地址的值。
若是地址,我們可以在記憶體中尋找該地址所對應的是什麼內容,於是我們有以下訪問地址操作:
查詢地址0x00 2d 9b 50 與 0x00 2d 9b 5c所對應的值
注:為何我在查詢地址的過程中將地址倆倆倒過來寫?因為由於我所用的計算機是小端機器,低地址存高位,所以在查記憶體時需要反過來寫。
查詢結果為:14和0c,那麼這兩個數字指向的地址值到底是代表什麼意思呢?
其實給它們分別為記錄對A的偏移量。
在虛繼承的過程中,派生類獨有資料之前都會有一個指標,這個指標指向一張名為“虛基表”的資料結構,該資料結構記錄了許多資訊,其中就會包括它們對於父類的偏移量,在我們D進行A成員函式操作的時候,找到地址,會尋找到A的成員函式地址,在進行Call呼叫,這樣就徹底的解決了菱形繼承的問題。