1、虛基類的作用從上面的介紹可知:如果一個派生類有多個直接基類,而這些直接基類又有一個共同的基類,則在最終的派生類中會保留該間接共同基類數據成員的多份同名成員。
在引用這些同名的成員時,必須在派生類對象名后增加直接基類名,以避免產生二義性,使其惟一地標識一個成員,如
c1.A::display( )。
在一個類中保留間接共同基類的多份同名成員,這種現象是人們不希望出現的。C++提供虛基類(virtual base class
)的方法,使得在繼承間接共同基類時只保留一份成員。
現在,將類A聲明為虛基類,方法如下:
class
A//聲明基類A
{…};
class B :virtual public
A//聲明類B是類A的公用派生類,A是B的虛基類
{…};
class C :virtual public
A//聲明類C是類A的公用派生類,A是C的虛基類
{…};
注意:
虛基類並不是在聲明基類時聲明的,而是在聲明派生類時,指定繼承方式時聲明的。因為一個基類可以在生成一個派生類時作為虛基類,而在生成另一個派生類時不作為虛基類。
聲明虛基類的一般形式為
class 派生類名: virtual 繼承方式
基類名
經過這樣的聲明后,當基類通過多條派生路徑被一個派生類繼承時,該派生類只繼承該基類一次。
需要注意: 為了保證虛基類在派生類中只繼承一次,應當在該基類的所有直接派生類中聲明為虛基類。否則仍然會出現對基類的多次繼承。
如果在派生類B和C中將類A聲明為虛基類,而在派生類D中沒有將類A聲明為虛基類,則在派生類E中,雖然從類B和C路徑派生的部分只保留一份基類成員,但從類D路徑派生的部分還保留一份基類成員。
2、虛基類的初始化如果在虛基類中定義了帶參數的構造函數,而且沒有定義默認構造函數,則在其所有派生類(包括直接派生或間接派生的派生類)中,通過構造函數的初始化表對虛基類進行初始化。例如
class
A//定義基類A
{
A(int i){ } //基類構造函數,有一個參數};
class B :virtual public A
//A作為B的虛基類
{
B(int n):A(n){ } //B類構造函數,在初始化表中對虛基類初始化
};
class C
:virtual public A //A作為C的虛基類
{
C(int n):A(n){ }
//C類構造函數,在初始化表中對虛基類初始化
};
class D :public B,public C
//類D的構造函數,在初始化表中對所有基類初始化
{
D(int n):A(n),B(n),C(n){ }
};
注意:
在定義類D的構造函數時,與以往使用的方法有所不同。規定:
在最后的派生類中不僅要負責對其直接基類進行初始化,還要負責對虛基類初始化。C++編譯系統只執行最后的派生類對虛基類的構造函數的調用,而忽略虛基類的其他派生類(如類B和類C)
對虛基類的構造函數的調用,這就保證了虛基類的數據成員不會被多次初始化。
溫馨提示:使用多重繼承時要十分小心,經常會出現二義性問題。許多專業人員認為:不要提倡在程序中使用多重繼承,只有在比較簡單和不易出現二義性的情況或實在必要時才使用多重繼承,能用單一繼承解決的問題就不要使用多重繼承。也是由於這個原因,有些面向對象的程序設計語言(如Java,Smalltalk)並不支持多重繼承。