菱形繼承,二義性和資料冗餘

2021-08-11 05:58:29 字數 2239 閱讀 5375

菱形繼承

我們都知道,c++中有單繼承和多繼承兩種繼承方式:

單繼承:如果乙個類只有乙個直接基類(也就是父類),我們稱這種繼承方式為單繼承。

多繼承:如果乙個類有多個父類(2個及其兩個以上),我們稱這種繼承方式為多繼承。

什麼是菱形繼承?

就講清楚菱形繼承,單單靠文字描述很難講清,所以直接上圖和**:

先看乙個最簡單的菱形繼承的**::

詳解:::

我們可以通過除錯看一下監視視窗:

什麼是二義性呢???

舉乙個很簡單的例子:::

int main()

編譯器會報錯,因為b和c都繼承了a,而且d繼承了b和c。所以d中會存在兩個a,那麼編譯器就不知道你指定的_a 是哪個類裡面的,所以會報錯說,呼叫不明確。

當然就想給b或者c中的_a賦值,還是有辦法的,那就是指定作用域。例如:

d.b

::_a = 1;

//b中的_a

d.c::_a = 2;

//c中的_a

那麼什麼又是資料冗餘呢?

資料冗餘是指資料之間的重複,也可以說是同一資料儲存在不同資料檔案中的現象。

也就是說d中存在兩個_a ,這種現象就叫做資料冗餘。

如果是常規的菱形繼承,就會導致二義性和 資料冗餘問題。那麼怎麼解決這一問題,c++中有一種方法:「用虛擬繼承解決」

能保證繼承後父類的記憶體布局只會存在乙份

#include 

using

namespace

std;

class a

public:

int _a;

};class b :virtual

public a//虛繼承

;class c:virtual

public a//虛繼承

;class d:public b,public c

int _d;

};int main()

實際上,我們可以抽象出它的物件模型

d中只存在乙份a,這樣就可以避免出現二義性和資料冗餘現象。

當然這些不是空口無憑的,我們可以在vs2008的環境下看看記憶體中到底是怎麼樣的?

實際上,如果將它的物件模型畫完整,那麼address會指向一塊空間:

我們也可以從彙編的層面上看:

知道了它的彙編,我們就能模擬實現求偏移量:

int tmp = 0;

d d;

tmp = *(

int*)((int

*)(*((int

*)(int

*)&d+2))+1);

printf("%d\n",tmp); //

12tmp = *(

int*)((int

*)(*(

int*)&d)+1);

printf("%d\n",tmp); //

20

C 繼承 二義性 虛繼承

繼承 子類擁有父類所有的成員變數和函式 子類是一種特殊的父類 子類可以當做父類的物件使用 子類可以擁有父類沒有的方法和屬性。class parent class child public parent int main 繼承的訪問控制 c 中的繼承方式會影響子類對外訪問屬性 1 看呼叫語句,是在類的...

python多繼承二義性

假如在多繼承中,父類a和父類b中有乙個同名的方法,子類呼叫的時候,呼叫哪個呢?class base object def test self print base class a base def test self print a class b base def test self print ...

C 多繼承的二義性

單繼承 派生類只從乙個基類派生 多繼承 派生類從多個基類派生 多重派生 有乙個基類派生出多個不同的派生類 多層派生 派生類又作為基類,繼續派生出新的類 多繼承可以看作是單繼承的擴充套件。所謂多繼承是指派生類具有多個基類,派生類與每個基類之間的關係仍可看作是乙個單繼承。多繼承下派生類的定義格式如下 c...