一、问题提出
多继承:一个子类有两个或者两个以上的父类称这个继承为多继承。
多继承中有一类特殊继承,那就是菱形继承;为什么特殊,因为菱形继承会导致访问成员的二义性和数据冗余。
#include<iostream>
class B{
public:
int _b;
};
class C1 :public B
{
public:
int _c1;
};
class C2 :public B
{
public:
int _c2;
};
class D:public C1,public C2
{
public:
int _d;
};
int main()
{
D d;
//d._b = 1;//这种会造成菱形继承访问成员变量不确定性,同样也会造成成员函数访问不确定性
//归结原因就是C1,C2都是继承的1同一个类
d.C1::_b = 1;//可以避免访问不确定性,但是不能避免数据冗余
d._c1 = 2;
d.C2::_b = 3;
d._c2 = 4;
d._d = 5;
return 0;
}
总结:菱形继承会造成数据冗余和成员访问不确定性。
二、虚拟继承
解决方法:虚拟继承解决数据冗余和二义性。继承虚拟关键字:virtual
虚拟继承原理:
一般赋值都是一条mov指令即可完成,但是基类对象需要三条指令
(1)先从对象前四个字节中取出偏移量表格的地址addr
(2)让addr向后偏移4个字节,并取出改地址空间的内容
(3)通过取到的基类对象相对于派生类对象起始位置的偏移量,然后根据取到的偏移量在派生类对象中找到基类成员。
虚拟继承:
(1)对象模型:派生类对象中多了四个字节,4个字节中存储的是偏移量表格地址。
偏移量表格:1、派生类对象相对于自己的偏移量 2、基类成员相对于派生类起始位置的偏移量
派生类在上,基类在下
(2)对基类成员的访问:借助偏移量表格中存储的基类成员相对于派生类对象起始位置的偏移量——来访问基类中的成员
(3)生成一个默认的构造函数:参数个数两个
参数1:1
参数2:对象空间地址
参数1作用:是否需要在对象的前四个字节中存放偏移量表格的地址(虚拟继承的标志)
三、菱形虚拟继承
菱形虚拟继承其主要目的就是是的基类成员只保存一份,防止发生二义性,同时也解决数据冗余。

的位置
class B{
public:
int _b;
};
class C1 :virtual public B
{
public:
int _c1;
};
class C2 :virtual public B
{
public:
int _c2;
};
class D:public C1,public C2
{
public:
int _d;
};
int main()
{
D d;
d._b = 1;
d._c1 = 2;
d._c2 = 3;
d._d = 5;
return 0;
}