可以使用作用域分辨符來來存放不同資料、進行不同操作,但也可以通過虛基類來維護一個成員副本。将共同基類設定為虛基類,這時不同路徑繼承過來的同名資料成員在記憶體中就隻有一個副本,同一個函數名也隻有一個映射。
虛基類成員在派生過程中和派生類一起維護同一個記憶體資料副本,這一點其實很好了解。
我們先來看一下沒有聲明虛基類的程式:
#include <iostream>
using namespace std;
class Base0{
public:
int var0;
void fun0(){cout<<"Member of Base0"<<endl;}
};
class Base1:public Base0{
public: //新增外部接口
int var1;
};
class Base2:public Base0{
public: //新增外部接口
int var2;
};
class Derived:public Base1,public Base2{
public: //新增外部接口
int var;
void fun(){cout<<"Member of Derived"<<endl;}
};
int main(){
Derived d;
d.var0=2;
d.fun0();
return 0;
}
程式顯然無法成功運作,錯誤原因:
request for member 'var0'(fun0) is ambiguous(不明确的)
,因為Base1和Base2都有
var0
和
fun0()
,程式不知道你調用的是哪一個類繼承下來的,除非你用作用域分辯符來唯一辨別,寫成:
d.Base1::var0=2;
d.Base1::fun0();
d.Base2::var0=3;
d.Base2::fun0();
這樣Base1和Base2類下的資料就分開存儲了,當然我們也可以使用虛基類技術進行共同存儲,也就是這幾個類共用一個
var0
和
fun0
副本,能節省不少記憶體空間。
虛基類的聲明隻是在類派生過程中使用
virtual
關鍵字,代碼如下:
#include <iostream>
using namespace std;
class Base0{
public:
int var0;
void fun0(){cout<<"Member of Base0"<<endl;}
};
class Base1:virtual public Base0{
public: //新增外部接口
int var1;
};
class Base2:virtual public Base0{
public: //新增外部接口
int var2;
};
class Derived:public Base1,public Base2{
public: //新增外部接口
int var;
void fun(){cout<<"Member of Derived"<<endl;}
};
int main(){
Derived d;
d.var0=2; //直接通路虛基類的資料成員
d.fun0(); //直接通路虛基類的函數成員
return 0;
}
這樣一來,程式就能成功運作:
這時的Derived類中,通過Base1,Base2繼承來的基類Base0中成員
var0
和
fun0
隻有一份副本,改變
var0
的值,就相當于改變Base1,Base2中的
var0
的值了。