菱形繼承及內部實現

2021-07-13 08:54:32 字數 2762 閱讀 2754

學習了c++的繼承後,覺得菱形繼承是比較難懂的一部分,通過了解菱形繼承,我們可以了解編譯器是如何工作的,下面介紹一下菱形繼承在記憶體中的實現方式。

首先簡單了解一下虛繼承,下面父類和子類的大小分別是多少?

class base

public:

int _a;

char a;

};class derive:virtual public base

virtual void fun2()

public:

int _b;

};

上述由於記憶體對齊,base類的大小為12,derive類的大小為24。

為什麼?是怎麼實現的呢?

由於類base中存在記憶體對齊,還包含了虛函式,則含有指向虛函式表的指標,故base類的大小為4+4+4=12。

類derive裡包含:繼承的虛函式類,該類的int _b,還有乙個指向虛基類的指標。考慮記憶體對齊,總大小為12+4+4=20,問題是多餘的4個位元組呢?下面通過介紹菱形繼承進行分析。

菱形繼承

typedef void (*func )();//定義函式型別指標

class base //超類

public:

int _a;

};class base1 :public base //父類

virtual void fun2()

public:

int _b;

};class base2 :public base //父類

virtual void fun3()

public:

int _c;

};class derive :public base1 ,public base2 //子類

virtual void fun2()

virtual void fun3()

virtual void fun4()

public:

int _d;

};void printtable(int * vtable )//列印出虛函式表

cout

cout 

cout 

cout 

//d._a = 1;此寫法存在二義性,無法訪問

d. base1::_a = 1; //不能從根本上解決二義性

d._b = 2;

d._c = 3;

d._d = 4;

int *vtable = (int*)&d;

int *vtable1 = (int*)*(int*)&d;

int *vtable2 = (int*)(*((int*)&d + sizeof(base1) / 4));

printtable(vtable1);

printtable(vtable2);

}菱形繼承

執行結果如下:

從監視可以看出:base1、base2中都有func1();base1的_vfptr與base2的_vfptr位址不同,指向的內容也不同。由於base1的虛表與base2的虛表都含有base的fun1(),這種繼承存在二義性與冗餘性。

菱形虛繼承解決了這個問題,

在定義 base1,base2時,需要在base1和base2類中的public base前加 virtual。

菱形虛繼承執行結果:

base1的_vfptr與base2的_vfptr位址相同,菱形虛擬繼承比菱形繼承多了乙個虛表,專門存放base,可見將超類存放乙份,通過指標使用該類,

這樣子類中父類與超類公共部分都是同一塊儲存空間,就解決了二義性與資料冗餘問題

虛基表指標_vfptr :0x0031f6c4和0xoo31f6d0

虛表指標_vfptr  :0x0031f6c8和0x0031f6d4

0x0031f6c8 + 0xfffffffc(-4) = 0x0031f6c4, 0x0031f6c8 + 0x00000018 = 0x0031f6e0; 

0x0031f6d4 + 0xfffffffc(-4) = 0x0031f6d0, 0x0031f6d4 + 0x0000000c = 0x0031f6e0.

結論如下:

在虛繼承時,每個類中會自動加乙個指標(_vfptr),該變數指向乙個全類共享的偏移量表。

如上圖所示偏移量的說明:如果該類有虛函式,那麼第一項記錄著當前子物件相對與虛基表指標的偏移,是ff ff ff fc(也就是-4),如果沒有則是零;第二項是被繼承的基類(base類)子物件(d._a)相對於虛表指標_vfptr的偏移量。

本文出自 「scen」 部落格,請務必保留此出處

複雜的菱形繼承及菱形虛擬繼承

乙個子類只有乙個直接父類時稱這個繼承關係為單繼承 乙個子類有兩個或兩個以上的直接父類時稱這個繼承方式為多繼承 菱形繼承是多繼承的一種特殊情況 菱形繼承的問題 1.冗餘 2.二義性 class person class student public person class teacher publi...

c 之多繼承及菱形繼承

c 允許乙個類繼承多個類,但在實際開發中並不建議去使用,可能會引發一些錯誤難以發現,比如菱形繼承 語法 class 子類 繼承方式 父類1 繼承方式 父類2 多繼承語法可能會引發父類中同名成員出現,子類使用時需要加作用域區分 菱形繼承的概念 兩個派生類繼承同乙個基類 又有某個類同時繼承兩個派生類 這...

菱形繼承 菱形虛擬繼承

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