多繼承(multiple inheritance)是指從多個直接基類中產生派生類的能力,多繼承的派生類繼承了所有父類的成員。儘管概念上非常簡單,但是多個基類的相互交織可能會帶來錯綜複雜的設計問題,命名衝突就是不可迴避的乙個。
多繼承時很容易產生命名衝突,即使我們很小心地將所有類中的成員變數和成員函式都命名為不同的名字,命名衝突依然有可能發生,比如典型的是菱形繼承,如下圖所示:
類 a 派生出類 b 和類 c,類 d 繼承自類 b 和類 c,這個時候類 a 中的成員變數和成員函式繼承到類 d 中變成了兩份,乙份來自 a-->b-->d 這條路徑,另乙份來自 a-->c-->d 這條路徑。
在乙個派生類中保留間接基類的多份同名成員,雖然可以在不同的成員變數中分別存放不同的資料,但大多數情況下這是多餘的:因為保留多份成員變數不僅占用較多的儲存空間,還容易產生命名衝突。假如類 a 有乙個成員變數 a,那麼在類 d 中直接訪問 a 就會產生歧義,編譯器不知道它究竟來自 a -->b-->d 這條路徑,還是來自 a-->c-->d 這條路徑。下面是菱形繼承的具體實現:
//間接基類a
class a;
//直接基類b
class b: public a;
//直接基類c
class c: public a;
//派生類d
class d: public b, public c //命名衝突
void setb(int b) //正確
void setc(int c) //正確
void setd(int d) //正確
private:
int m_d;
};int main()
這段**實現了上圖所示的菱形繼承,第 25 行**試圖直接訪問成員變數 m_a,結果發生了錯誤,因為類 b 和類 c 中都有成員變數 m_a(從 a 類繼承而來),編譯器不知道選用哪乙個,所以產生了歧義。
void seta(int a)這樣表示使用 b 類的 m_a。當然也可以使用 c 類的:
void seta(int a)為了解決多繼承時的命名衝突和冗餘資料問題,c++ 提出了虛繼承,使得在派生類中只保留乙份間接基類的成員。
在繼承方式前面加上 virtual 關鍵字就是虛繼承,請看下面的例子:
//間接基類a
class a;
//直接基類b
class b: virtual public a;
//直接基類c
class c: virtual public a;
//派生類d
class d: public b, public c //正確
void setb(int b) //正確
void setc(int c) //正確
void setd(int d) //正確
private:
int m_d;
};int main()
這段**使用虛繼承重新實現了上圖所示的菱形繼承,這樣在派生類 d 中就只保留了乙份成員變數 m_a,直接訪問就不會再有歧義了。
虛繼承的目的是讓某個類做出宣告,承諾願意共享它的基類。其中,這個被共享的基類就稱為虛基類(virtual base class),本例中的 a 就是乙個虛基類。在這種機制下,不論虛基類在繼承體系**現了多少次,在派生類中都只包含乙份虛基類的成員。
參考:
C 虛繼承和虛基類詳解
多繼承 multiple inheritance 是指從多個直接基類中產生派生類的能力,多繼承的派生類繼承了所有父類的成員。儘管概念上非常簡單,但是多個基類的相互交織可能會帶來錯綜複雜的設計問題,命名衝突就是不可迴避的乙個。多繼承時很容易產生命名衝突,即使我們很小心地將所有類中的成員變數和成員函式都...
虛繼承和虛基類
虛繼承主要解決在多重繼承中的菱形繼承問題,也就是說 b和c類同時繼承了a類,然後d類繼承了b,c類,那麼d類的虛表就會有重複的函式指標。include using namespace std 虛基類 class person person person string name name name e...
虛基類和虛繼承
這算得上我個人的乙個總結上,其實也算不上什麼原創,只是為了過濾一下前輩的經驗,加深一下自己的記憶 虛繼承的目的是讓某個類做出宣告,承諾願意共享它的基類,被共享的那個基類就是虛基類 includeusing namespace std class a protected int a class b p...