二義性問題
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...