菱形繼承和菱形虛繼承

2021-07-30 06:07:30 字數 2153 閱讀 6355

繼承是c++的一大特點,我們通過菱形繼承和菱形虛繼承對繼承進行進一步的分析。

【菱形繼承】

建立乙個基類a讓b1和b2公有繼承於它,讓c公有繼承b1和b2。

class a

~a()

int a;

};class b1 : public a

~b1()

int b1;

};class b2 : public a

~b2()

int b2;

};class c : public b1,public b2

~c()

int c;

};

我們可以通過記憶體觀察c類物件的記憶體結構,如下圖:

我們可以觀察到在c類物件建立成功後,c類物件包含了b1和b2類成員,b1和b2的成員中又包含了a類的成員,那麼在物件的構造時具體是怎樣的過程呢?

利用反彙編檢視彙編**進行分析,如下圖:

去掉了一些其他資訊,發現在建立c類物件時,先去呼叫了b1類的建構函式,在b1的建構函式中又去呼叫了a類的建構函式,返回c類的建構函式中後接著呼叫b2的建構函式,在b2的建構函式中又去呼叫a的建構函式。

析構函式的呼叫與建構函式的呼叫順序相反(先建立後銷毀)

我們可以通過列印資訊驗證進一步驗證:

注意:可以通過彙編**看到,在執行派生類建構函式的初始化列表之前就去呼叫了基類的建構函式。

問題:【菱形虛擬繼承】

c++中引入了虛繼承來解決上面的二義性問題和資料冗餘的問題。虛擬繼承的目的是讓某個類作出宣告,承諾願意共享它的基類。

建立乙個基類a讓b1和b2虛繼承於它,讓c公有繼承b1和b2,這時b1和b2就共享了基類a。

class a

~a()

int a;

};class b1 :virtual public a

~b1()

int b1;

};class b2 : virtual public a

~b2()

int b2;

};class c : public b1,public b2

~c()

int c;

};

我們可以觀察c類物件在記憶體中的儲存結構:

b1和b2都被實現為對a類的虛繼承,說明b1和b2共享了基類的成員,但是我們可以通過上圖觀察到a類成員既沒有和b1類連續也沒有和b2類連續,那麼怎樣訪問b1和b2中繼承於a類的成員呢?這就用到了b1和b2成員中多出來的那個位址,我們開啟記憶體視窗進行觀察:

注意:如果乙個派生類虛繼承於乙個基類那麼在建立派生類物件時,會在物件前四個位元組中加入乙個位址,指向乙個表,這個表中存放了兩個偏移量,相對於自己的偏移量和相對於基類的偏移量,可以通過偏移量來找到共享的基類成員。

進一步對建立c類物件的建立過程進行分析:

我們通過檢視彙編**進行分析

可以通過彙編**看到,在建立c類物件時,在執行c類建構函式的初始化列表之前分別呼叫了a類、b1類和b2類的建構函式,並沒有在b1和b2的建構函式中呼叫a類的建構函式,也就保證了只建立出了乙份a類成員。

我們可以通過列印資訊進一步驗證:

菱形繼承和虛繼承

1.菱形繼承 菱形繼承概念圖 菱形繼承物件模型 參照菱形繼承物件模型,不難發現若呼叫dd類時,裡面包含兩個相同的aa類的所有成員,在呼叫過程中會出現二義性和資料冗餘的問題,為了解決上述問題,我們提出了虛繼承。接下來通過簡單例項 講解虛函式及底層實現。樣例 include using namespac...

菱形繼承 菱形虛擬繼承

菱形繼承 鑽石繼承 模型 拿如下 舉例 class person class student public person class teacher public person class graduate public student,public teacher void test 當派生類gr...

C 多繼承 菱形繼承 虛繼承

b和c都單繼承了a d繼承了b和c 是多繼承 有兩個或兩個以上的基類就是多繼承 class a public int ma class b public a public int mb class c public a public int mc class d public b,public c ...