C++ 虛繼承和虛繼承

C++ 虛繼承和虛繼承

虛繼承是在多繼承中爲了解決衝突而技術。學術一點來講,是指一個指定的基類,在繼承體系結構中,將其成員數據實例共享給也從這個基類直接或間接派生的其餘類。c++

虛繼承很是有用,能夠避免多繼承的歧義和多重拷貝。函數

爲何須要虛繼承?

考慮有以下繼承結構。學習

圖源Wiki

B和C繼承A,D多繼承B、C,咱們看如下代碼。code

class A {
public:
	virtual void sayHi();
};

class B :public A {
public:
	virtual void onlyB();
};

class C :public A {
public:
	virtual void onlyC();
};

class D :public B, public C {

};

到這裏,可能聰明的讀者已經看出來有什麼問題了。若是咱們對D進行實例化。對象

D d;
A& a = d;

這麼寫的話,編譯器會無情的報錯。例如VS2019就會說這是一種不明確的轉換。沒錯,由於按照上面的定義,D是一個有歧義的類。由於D間接地繼承了兩次A(B繼承了,C繼承了,D又繼承了B和C),因此全部的D對象就會有兩個不一樣的由A派生的派生對象(B和C)。所以,嘗試直接對其進行引用,編譯器會一頭霧水,這個引用究竟是想指向哪一個A啊?到底是 B::A 仍是 C::A ?因此這樣是不對的。blog

固然,咱們可使用static_cast進行強制類型轉換,可是這不是咱們今天學習的目標。繼承

咱們能夠看到,咱們不須要兩個A,不須要A被繼承兩次。咱們只是須要一個層次結構來講明A、B、C、D之間的關係。假如A是職業,B是銷售,C是經理,咱們僅僅想表示D是一個銷售經理。而不意味着D是兩個A,銷售經理是一種職業而不是兩種職業。並且從上面這個特殊的例子來看,B和C並無重載sayHi()這個函數,sayHi()繼承到D這裏還是以前那套運做規律,因此咱們也不須要兩份如出一轍的sayHi()。編譯器

因而,虛繼承便橫空出世來解決這個問題了。編譯

虛繼承

咱們若是這麼聲明繼承,ast

class A {
public:
	virtual void sayHi();
};

// virtual
class B :public virtual A {
public:
	virtual void onlyB();
};

class C :virtual public A {
public:
	virtual void onlyC();
};

class D :public B, public C {

};

若是在繼承的類以前加上一個virtual關鍵詞,表明該繼承是虛繼承。這樣 B::A 和 C::A 如今是一個A了。這樣,D中有且僅有一個共享的A。至關於間接派生類D直接穿透它的基類B和C,直接繼承了A。這樣,若是再建立A對D的引用,也不會有歧義了。由於只存在一種能夠轉換路徑,那就是直接由A到D。

這個A就是所說的虛基類。因爲虛基類是多個派生類共享的基類,所以必須明確到底誰來初始化這個虛基類。C++標準規定,由最後派生的類來初始化虛基類。所以,對於間接繼承了虛繼類的類,也必須能直接訪問虛繼承來的祖先類,可以訪問其虛函數表。

例如,以前的例子當中,B和C、D的構造函數初始化列表中均可以給出虛基類的初始化,可是隻能由D的構造函數執行虛基類的初始化。

相關文章
相關標籤/搜索