當一個基類被聲明為虛基類後,即使它成為了多繼承鍊路上的公共基類,最後的派生類中也隻有它的一個備份。例如:
class CBase { };
class CDerive1:virtual public CBase{ };
class CDerive2:virtual public CBase{ };
class CDerive12:public CDerive1,CDerive2{ };
則在類CDerive12的對象中,僅有類CBase的一個對象資料
虛基類的特點:
虛基類構造函數的參數必須由最新派生出來的類負責初始化(即使不是直接繼承);
虛基類的構造函數先于非虛基類的構造函數執行。
重寫“C++學習筆記(9)——使用範圍運算符解決繼承中的二義性問題 ”中的程式,觀察虛基類的作用
代碼如下:
[cpp] view plain copy
- #include <IOSTREAM.H>
- //基類
- class CBase
- ...{
- protected:
- int a;
- public:
- CBase(int na)
- ...{
- a=na;
- cout<<"CBase constructor! ";
- }
- ~CBase()...{cout<<"CBase deconstructor! ";}
- };
- //派生類1(聲明CBase為虛基類)
- class CDerive1:virtual public CBase
- ...{
- public:
- CDerive1(int na):CBase(na)
- ...{
- cout<<"CDerive1 constructor! ";
- }
- ~CDerive1()...{cout<<"CDerive1 deconstructor! ";}
- int GetA()...{return a;}
- };
- //派生類2(聲明CBase為虛基類)
- class CDerive2:virtual public CBase
- ...{
- public:
- CDerive2(int na):CBase(na)
- ...{
- cout<<"CDerive2 constructor! ";
- }
- ~CDerive2()...{cout<<"CDerive2 deconstructor! ";}
- int GetA()...{return a;}
- };
- //子派生類
- class CDerive12:public CDerive1,public CDerive2
- ...{
- public:
- CDerive12(int na1,int na2,int na3):CDerive1(na1),CDerive2(na2),CBase(na3)
- ...{
- cout<<"CDerive12 constructor! ";
- }
- ~CDerive12()...{cout<<"CDerive12 deconstructor! ";}
- };
- void main()
- ...{
- CDerive12 obj(100,200,300);
- //得到從CDerive1繼承的值
- cout<<" from CDerive1 : a = "<<obj.CDerive1::GetA();
- //得到從CDerive2繼承的值
- cout<<" from CDerive2 : a = "<<obj.CDerive2::GetA()<<endl<<endl;
- }
1. 子派生類對象的值:

從上例可以看出,在類CDerived12的構造函數初始化表中,調用了間接基類CBase的構造函數,這對于非虛基類是非法的,但對于虛基類則是合法且必要的。
對于派生類CDerived1和CDerived2,不論是其内部實作,還是執行個體化的對象,基類CBase是否是它們的虛基類是沒有影響的。受到影響的是它們的派生類CDerived12,因為它從兩條路徑都能到達CBase。
2. 運作結果:
由此可知,其公共基類的構造函數隻調用了一次,并且優先于非基類的構造函數調用;并且發現,子派生類的對象obj的成員變量的值隻有一個,是以,當公共基類CBase被聲明為虛基類後,雖然它成為CDerive1和CDerive2的公共基類,但子派生類CDerive12中也隻有它的一個備份。可以仔細比較與例2的運作結果有什麼不同。