由於C++中允許多繼承,所以會出現二義性問題:在多個衍生類別中,定義了相同名字的方法,這時再在main函數裡面通過基類調用該方法時,編譯器就犯難了。因為它不知道你到底是想用哪一個衍生類別裡面的方法。
那麼,現在又有了一個問題:假如有兩個衍生類別DerivedA和DerivedB,它們的同名方法一個有參數,一個沒有參數,是不是不會出現二義性問題了?
或者說,這兩個衍生類別方法的一個是private,一個是public,是不是就可以防止二義性了呢?
答案是否定的。二義性的檢查應在存取控制許可權或者類型檢查之前進行,因此存取控制許可權不同或類型不同不能解決二義性問題。
既然上述提出的假設成立,那麼應該怎樣去有效解決二義性問題呢?
虛基類就是為了這個解決這種二義性問題提出來的。
二義性產生的最主要原因是:基類在衍生類別中產生了兩個子物件,從而導致了對基類成員訪問的不唯一性。所以只需要使公用基類只產生一個子物件,就可以了。
也就是說,保證虛基類建構函式只被調用一次即可。虛基類自對象是由最衍生類別的建構函式通過調用虛基類的建構函式實現,此時,最衍生類別的所有基類中列出的對虛基類的建構函式的調用在執行過程中都將被忽略,而從保證對虛基類自對象值初始化一次。同時,最衍生類別的初始化列表必須列出對虛基類建構函式的調用;如果未列出,則表示使用該虛基類的預設建構函式。
(在繼承結構的層次中,建立的對象屬於這個結構中間的某個類,建立對象時所制定的類就是最衍生類別)
下面通過一個小例子分析一下:
#include <iostream>using namespace std;//基類class Base{//公有成員public:Base(char i){cout << "Base's cons." << i<< endl;}~Base(){cout << "Base's des." << endl;}};//衍生類別1class Derivedl1:virtual public Base{//公有成員public:Derivedl1(char i,char j):Base(i){cout << "Derivedl1's cons." << j<< endl;}~Derivedl1(){cout << "Derived's des." << endl;}//私人成員private:char b;};//衍生類別2class Derivedl2:virtual public Base{//公有成員public:Derivedl2(char i,char j):Base(i){cout << "Derivedl2' cons." << j <<endl;}~Derivedl2(){cout << "Derived12' des." << endl;}};//繼承基類Base的衍生類別class Derived2: public Derivedl1,public Derivedl2{//公有成員public :Derived2(char i,char j,char k,char l,char m,char n):Derivedl2(k,l),Derivedl1(i,j),Base(i),aa(m){cout << "Derived2's cons." <<n << endl; }~Derived2(){cout << "Derived2's des." << endl;}//私人成員private :Base aa;};//main函數int main() {Derived2 obj('a','b','c','d','e','f');return 0;}
Main()中定義Derived2類對象obj,要調用它的構造方法。由於該類存在一個成員對象aa,且根據C++的規定,Derived類先調用虛基類Base,然後再調用兩個直接基類Derivedl1和Derivedl2;然後在調用成員對象的建構函式初始化成員對象aa;最後再執行衍生類別Derived2的建構函式。
直接基類的執行順序取決於定義衍生類別時聲明基類的順序,而與衍生類別建構函式的初始化列表順序無關,所以先執行Derivedl1,後執行Derivedl2。
類Derivedl1也是一個衍生類別,它繼承Base虛基類。而由於它的樣本已經存在於最衍生類別Derived2,所以後面的調用不會再執行。
同時解構函式的執行順序與建構函式嚴格相反。所以,該程式的執行解決是:
本文主要介紹瞭解決C++中二義性問題一種方案——虛基類。路過的童鞋希望留下寶貴意見。