class CFurniture
{
public:
CFurniture(): m_iWeith( 3){ cout <<"construction of CFurniture/n";}
void SetWidth( int iWeight)
{
m_iWeith= iWeight;
}
void GetWidth( )
{
cout << m_iWeith << endl;
}
protected:
int m_iWeith;
};
class CBed : virtual public CFurniture //
{
public:
void SetWidth( int iWeight)
{
m_iWeith= iWeight;
}
};
class CSofa : virtual public CFurniture //
{
public:
void SetWidth( int iWeight) //如果CBed和CSofa都用虚拟继承,则CBed和CSofa不能同时有该方法(即至少一个加注释)
{
m_iWeith= iWeight;
}
};
class CSofaBed: public CSofa, public CBed
{
public:
void SetWidth( int iWeight)//如果是虚继承,则会调用此处,不会调用基类的该函数;如果此段函数注释,则会调用基类的函数.
{
m_iWeith= iWeight;
}
};
int _tmain(int argc, _TCHAR* argv[])
{
CSofaBed mySB;
mySB.SetWidth( 10);//用虚拟继承,则调用基类的该方法;如果CSofaBed类中重载了SetWidth(),则调用CSofaBed类中重载的SetWidth().即自己重载了,则调用自己的;如果没有重载,则调用虚拟继承的基类的函数
mySB.GetWidth( );
system("pause");
return 0;
}
注:
(1)用虚拟继承,基类CFurniture的构造函数只被调用一次.而不用虚拟继承,则会调用二次CFurniture的构造函数.
(2)不用虚拟继承,则会出现二个对象的变量m_iWeith(CBed和CSofa各一个),故编译器不知道调用哪个,基类CFurniture的构造函数也会调用二次;而如果用虚拟继承,相当于共享数据,即相当于只有一个m_iWeith,且基类CFurniture的构造函数只会调用一次.
------------------------------------------------------------------
网上摘录:
为了解决从不同途径继承来的同名的数据成员在内存中有不同的拷贝造成数据不一致问题,将共同基类设置为虚基类。这时从不同的路径继承过来的同名数据成员在内存中就只有一个拷贝,同一个函数名也只有一个映射。这样不仅就解决了二义性问题,也节省了内存,避免了数据不一致的问题。
class 派生类名:virtual 继承方式 基类名
virtual是关键字,声明该基类为派生类的虚基类。
在多继承情况下,虚基类关键字的作用范围和继承方式关键字相同,只对紧跟其后的基类起作用。
声明了虚基类之后,虚基类在进一步派生过程中始终和派生类一起,维护同一个基类子对象的拷贝。
对于如下的继承关系。class a{ public: int i;}; class b:public a{}; class c:public a{}; class d:public b,public c{};上述的继承体系中,由于类b和类c都是一般的继承于a,所以在b、c两个类对象中,都会有其基类a的数据i的一份拷贝。也就是int b::i和 int c::i,而此时类d继承于b和c,所以,类d中就会有两份i的数据,一份继承与b而来,另一份继承于c而来,所以对于d来说,这是冗余的,如果类b和c都是virtual public a的话,那么在类d中,就只有一份数据。而且无论以后怎么继承,a都只有一份。
其实虚拟继承的实现因编译器不同而不同,基本上都是用virtual base指针来实现的,只是这个指针的位置放在哪个地方而异。
默认继承:
base base
| |
| |
Mid1 Mid2
| |
| |
Child
存在两个类体系是出错的原因.
虚拟继承:
base
| |
| |
Mid1 Mid2
| |
| |
Child
使用虚拟继承将类的体系整合起来.