可以使用作用域分辨符来来存放不同数据、进行不同操作,但也可以通过虚基类来维护一个成员副本。将共同基类设置为虚基类,这时不同路径继承过来的同名数据成员在内存中就只有一个副本,同一个函数名也只有一个映射。
虚基类成员在派生过程中和派生类一起维护同一个内存数据副本,这一点其实很好理解。
我们先来看一下没有声明虚基类的程序:
#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
的值了。