繼承中的二義性問題

2021-09-12 15:05:48 字數 1636 閱讀 2242

一、呼叫不同基類的同名成員時可能出現二義性

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...