繼承是面向?qū)ο笳Z言的一大特性,在C++中既有單繼承,當(dāng)然也會存在多繼承。那么多繼承是怎么實現(xiàn)的及多繼承的一些缺點,將是這篇博客想要說的內(nèi)容。
多繼承最典型的一個例子就是菱形繼承,那什么又是菱形繼承呢?就是有兩個子類分別繼承一個父類,而有存在一個子類同時這兩個子類。圖示如下。 
當(dāng)我們模擬出菱形繼承想給a賦值時,就會發(fā)現(xiàn)一個問題,我們到底是從哪個類去訪問的BaseClass中的a?這時就會產(chǎn)生二義性。也就是說在內(nèi)存中會出現(xiàn)兩個BaseClass,結(jié)構(gòu)圖如下。


代碼運行后調(diào)監(jiān)視窗口如上,可明顯看到d中存在了兩個a,這也會存在數(shù)據(jù)冗余的問題。那怎么去解決這個問題?此時,C++又提出了另一個新概念——虛擬繼承。虛擬繼承使得在繼承間接共同基類的時候只保留一份成員。接下來的篇幅將會說明虛擬繼承的實現(xiàn)。
class A{public: int a;};class B : virtual public A{public : int b;};class C : virtual public A{public: int c;};class D : public B, public C{public: int d;};int main(){ D d; d.B::a = 0; d.C::a = 1; d.B::b = 2; d.C::c = 3; d.D::d = 4; cout << (sizeof(d)) << endl; system("pause"); return 0;}運行上述代碼后,在內(nèi)存中會出現(xiàn)以下的情形,如下圖。 
原來大小為20的d如今變成了24,按理說當(dāng)我們采用了虛擬繼承,解決了數(shù)據(jù)冗余問題,所占的空間應(yīng)該也會變小,但如今反而變大了,這是怎么回事呢?
我們在細(xì)看第一行和第三行,發(fā)現(xiàn)了這兩個數(shù)字比較接近,仔細(xì)看更像是一個地址。于是,在內(nèi)存中查看會發(fā)現(xiàn)如下圖所示的情形。

在這兩個內(nèi)存緊挨著的地方,出現(xiàn)了一個“14”和“0c”,也就是說在這個地方存了這兩個數(shù)字。那么我們就可以猜測一下,在虛擬繼承中,菱形繼承的結(jié)構(gòu)是如下圖的。

BaseClass并不是按照我們所想象那樣存在最上面的,而是存放在最底下,而原來存BaseClass的地方存了兩個“數(shù)字”。仔細(xì)觀察,不難發(fā)現(xiàn)這兩個數(shù)字是距離BaseClass的位移,也就是我們所說的偏移量。
其實,講到這里的時候,大家應(yīng)該也就明白了,在虛擬繼承中是通過存儲基類的偏移量來解決數(shù)據(jù)冗余的問題,以空間換時間解決菱形繼承存在的問題。
新聞熱點
疑難解答