一、呼叫不同基類的同名成員時可能出現二義性
class a
;class b
;class c:public a,public b
;
在執行obj.get();時將是有二義性的。因為類c分別從類a類b繼承了兩個不同版本的get()成員函式,因此,obj.get();到底呼叫哪個get()版本,編譯器將無從知曉。
對於這種二義性問題,常見有兩種解決方法:
(1)使用作用域分辨符::加以消除。
obj.a::get();
obj.b::get();
(2)在類c中也定義成員函式get()函式,則有類c的物件obj訪問get()函式obj.get()沒有二義性,這是因為當派生類中的成員與基類中的成員重名時,派生類中的同名成員將被呼叫。
class a
;class b
;class c:public a,public b
;
二、訪問共同基類的成員時可能出現二義性
當乙個派生類有多個基類,而這些基類又有乙個共同的基類時,也就是所謂的菱形繼承。這時對這個共同基類中成員的訪問可能出現二義性。
class a
;class b1:public a
;class b2:public a
;class c:public b1,public b2
;
在此類結構下,如果建立類c的物件c1:
c c1;
則下面的兩個訪問都有二義性:
c1.disp();
c1.a::disp();
這是因為b1,b2分別從類a中繼承了乙個disp()成員函式的副本,因此類c中就有了分別從類b1,b2兩條不同路線上繼承過來的disp()版本,儘管這兩個版本的函式完全相同,但是語句「c1.disp();」將使編譯器無從知曉到底呼叫從類b1繼承來的disp(),還是呼叫從類b2繼承來的disp(),這就是導致二義性的原因。
語句「c1.a::disp();」產生二義性的道理相同,不過下面的兩條呼叫語句卻是正確的:
c1.b1::disp();
c1.b2::disp();
因為通過「b1::」及「b2::」的限定,明確告訴編譯器應該呼叫從哪條路徑上繼承過來的disp()。
在乙個類中保留間接共同基類 的多份同名成員,雖然有時是必要的,可以在不同的資料成員中分別存放不同的資料,也可以通過建構函式分別對它們進行初始化。但在大多數情況下,這種現象是人們不希望出現的。
因為保留多份資料成員的副本,不僅占用較多的儲存空間,還增加了訪問這些成員時的困難。而且在實際上,並不需要有多份副本,為此,c++中提供了虛基類(virtual base class)技術來解決這個問題。
class a
int a;
void disp()
};class b1:virtual public a
int b1;
};class b2:virtual public a
int b2;
};class c:public b1,public b2
int c;
void dispc()
};int main()
C 多層繼承二義性問題
多繼承可以看作是單繼承的擴充套件。所謂多繼承是指派生類具有多個基類,派生類與每個基類之間的關係仍可看作是乙個單繼承。多繼承下派生類的定義格式如下 class 派生類名 繼承方式1 基類名1 繼承方式2 基類名2 其中,繼承方式1 繼承方式2 是三種繼承方式 public private protec...
C 多層繼承二義性問題
多繼承可以看作是單繼承的擴充套件。所謂多繼承是指派生類具有多個基類,派生類與每個基類之間的關係仍可看作是乙個單繼承。多繼承下派生類的定義格式如下 class 派生類名 繼承方式1 基類名1 繼承方式2 基類名2 其中,繼承方式1 繼承方式2 是三種繼承方式 public private protec...
C 多繼承二義性問題
c 中的多繼承帶來的二義性問題 本文 出現二義性的原因 派生類在訪問基類成員函式時,由於基類存在同名的成員函式,導致無法確定訪問的是哪個基類的成員函式,因此出現了二義性錯誤。什麼是多重繼承的二義性 class a class b class c public a,public b 如果宣告 c c1...