-
虛基類
鎖定
當在多條繼承路徑上有一個公共的基類,在這些路徑中的某幾條匯合處,這個公共的基類就會產生多個實例(或多個副本),若只想保存這個基類的一個實例,可以將這個公共基類説明為虛基類。
- 中文名
- 虛基類
- 繼 承
- 類繼承了基類多次
- 產 生
- 多個拷貝
- 原則是
- 在內存中只有基類成員的一份拷貝
虛基類技術簡介
在繼承中產生歧義的原因有可能是繼承類繼承了基類多次,從而產生了多個拷貝,即不止一次的通過多個路徑繼承類在內存中創建了基類成員的多份拷貝。虛基類的基本原則是在內存中只有基類成員的一份拷貝。這樣,通過把基類繼承聲明為虛擬的,就只能繼承基類的一份拷貝,從而消除歧義。用virtual限定符把基類繼承説明為虛擬的。
class x1:virtual public x
//……
;
class x2:virtual public x
//……
;
虛基類初始化
(1)虛基類的構造函數在非虛基類之前調用;
(2)若同一層次中包含多個虛基類,這些虛基類的構造函數按它們説明的次序調用;
(3)若虛基類由非虛基類派生而來,則仍先調用基類構造函數,再調用派生類的構造函數。
虛基類C++
在派生類繼承基類時,加上一個virtual關鍵詞則為虛擬基類繼承,如:
class derive:virtual public base { };
虛基類主要解決在多重繼承時,基類可能被多次繼承,虛基類主要提供一個基類給派生類,如:
#include <iostream> using namespace std; class B0// 聲明為基類B0 { int nv;//默認為私有成員 public://外部接口 B0(int n){ nv = n; cout << "Member of B0" << endl; }//B0類的構造函數 void fun(){ cout << "fun of B0" << endl; } }; class B1 :virtual public B0 { int nv1; public: B1(int a) :B0(a){ cout << "Member of B1" << endl; } }; class B2 :virtual public B0 { int nv2; public: B2(int a) :B0(a){ cout << "Member of B2" << endl; } }; class D1 :public B1, public B2 { int nvd; public: D1(int a) :B0(a), B1(a), B2(a){ cout << "Member of D1" << endl; }// 此行的含義,參考下邊的 “使用注意5” void fund(){ cout << "fun of D1" << endl; } }; int main(void) { D1 d1(1); d1.fund(); d1.fun(); return 0; }
執行結果:
Member of B0
Member of B1
Member of B2
Member of D1
fun of D1
fun of B0
這裏D1在B1,B2上繼承,間接繼承B0,D1繼承的成員變量有nv、nv1、nv2,並且只繼承一次,若不是由虛基類繼承而來,那麼nv會被D1從B1和B2各繼承一次,造成冗餘。
虛基類使用注意
(1) 一個類可以在一個類族中既被用作虛基類,也被用作非虛基類。
(2) 在派生類的對象中,同名的虛基類只產生一個虛基類子對象,而某個非虛基類產生各自的子對象。
(3) 虛基類子對象是由最遠派生類的構造函數通過調用虛基類的構造函數進行初始化的。
(4) 最遠派生類是指在繼承結構中建立對象時所指定的類。
(6) 從虛基類直接或間接派生的派生類中的構造函數的成員初始化列表中都要列出對虛基類構造函數的調用。但僅僅用建立對象的最遠派生類的構造函數調用虛基類的構造函數,而該派生類的所有基類中列出的對虛基類的構造函數的調用在執行中被忽略,從而保證對虛基類子對象只初始化一次。
(7) 在一個成員初始化列表中同時出現對虛基類和非虛基類構造函數的調用時,虛基類的構造函數先於非虛基類的構造函數執行。