C 二義性問題

2021-06-27 04:59:46 字數 3985 閱讀 4671

二義性問題

1.在繼承時,基類之間、或基類與派生類之間發生成員同名時,將出現對成員訪問的不確定性——同名二義性。

2.當派生類從多個基類派生,而這些基類又從同乙個基類派生,則在訪問此共同基類中的成員時,將產生另一種不確定性——路徑二義性。

同名二義性

同名隱藏規則——解決同名二義的方法

當派生類與基類有同名成員時,派生類中的成員將遮蔽基類中的同名成員。

若未特別指明,則通過派生類物件使用的都是派生類中的同名成員;

如要通過派生類物件訪問基類中被遮蔽的同名成員,應使用基類名限定(::)。

多繼承同名隱藏舉例

[cpp]view plain

copy

//多繼承同名隱藏舉例

#include 

using

namespace

std;  

class

b1//宣告基類b1

;  class

b2//宣告基類b2

;  class

d1: 

public

b1, 

public

b2  

;  void

main()    

同名二義性的解決方法

解決方法一:用類名來限定c1.a::f() 或c1.b::f()

解決方法二:同名覆蓋,再造介面在c 中再宣告乙個同名成員函式f(),該函式根據需要呼叫a::f() 或b::f()

路徑二義性

為了解決路徑二義性問題,引入虛基類

–用於有共同基類的多繼承場合(多層共祖) 宣告

–以virtual修飾說明共同的直接基類

例:class b1: virtual public b

作用–用來解決多繼承時可能發生的對同一基類繼承多次和多層而產生的二義性問題.

–為最遠的派生類提供唯一的基類成員,而不重複產生個副本。

注意:–在第一級繼承時就要將共同基類設計為虛基類。

虛基類舉例

class b ;

class b1 : virtual public b ;

class b2 : virtualpublic b ;

class c: public b1, public b2;

在子類物件中,最遠基類成分是唯一的。於是下面的訪問是正確的:

c cobj;

cobj.b;

使用最遠基類成員原則

[cpp]view plain

copy

//使用最遠基類成員原則

#include 

using

namespace

std;  

class

b0//宣告基類b0

;  class

b1: 

virtual

public

b0 //b0為虛基類,派生b1類

;  class

b2: 

virtual

public

b0 //b0為虛基類,派生b2類

;  class

d1: 

public

b1, 

public

b2//派生類d1宣告

;  void

main()

//程式主函式  

執行結果:

member of b0

press any key to continue

有虛基類時的建構函式的呼叫次序:

無論虛基類與產生物件的派生類相隔多遠,首先呼叫虛基類的建構函式;

然後按繼承次序呼叫直接基類的建構函式;

如果有包含的物件,再按宣告次序呼叫所包含物件類的建構函式;

最後才是普通型別資料成員的初始化。

有虛基類時的建構函式舉例

[cpp]view plain

copy

//有虛基類時的建構函式舉例

#include 

using

namespace

std;  

class

b0//宣告基類b0

intnv;  

void

fun();  

class

b1: 

virtual

public

b0  

intnv1;  

};  

class

b2: 

virtual

public

b0  

intnv2;  

};  

class

d1: 

public

b1, 

public

b2  

intnvd;  

void

fund();  

void

main()    

執行結果:

b0's constructor called

b1's constructor called

b2's constructor called

b0's constructor called

b1's constructor called

b0's constructor called

b2's constructor called

d1's constructor called

member of b0

press any key to continue

「二義性」的回顧

凡是編譯器訪問或呼叫時有多於一項的合法選擇,這種會讓編譯器舉棋不定的**叫具二義性的**。

二義性的發生場合:

1.帶預設形參值的函式與同名的過載函式相遇時;

[cpp]view plain

copy

//帶預設形參值的函式與同名的過載函式相遇時

#include 

using

namespace

std;  

void

funct (

inti, 

long

=2,float

f=3);     

//函式原型中預設值可省去形參名

void

funct (

inti, 

long

l)      

void

main()  

void

funct (

inti, 

long

l,float

f)    

2.繼承時的同名二義;

3.多層共祖的路徑二義;

4.形實結合時的型別相容;

[cpp]view plain

copy

//形實結合時的型別相容;

#include 

using

namespace

std;  

void

fun ( 

inta)  

執行結果:

fun(int)

fun(char)

fun(int)

fun(char)

press any key to continue

5.使用者自定義型別的轉換時。 如

class b;

class a 

//建構函式 };

class b 

//型別轉換函式 };

void fun ( const a &);

b b;fun ( b ); // 到底呼叫哪個函式?  型別轉換函式還是建構函式

解決:1。給a的建構函式前加explicit ,關閉自動轉換功能;2。不提供或不直接提供b類的轉換函式。

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