目录
菱形继承:菱形继承是多继承的一种特殊情况。
1、 菱形继承的弊端:造成数据冗余以及二义性。
下面我们以一段简单的代码从内存中看一看问题:
class A
{
public:
int _a;
int _A = 10;
};
class B : public A
//class B : virtual public A
{
public:
int _b;
};
class C : public A
//class C : virtual public A
{
public:
int _c;
};
class D : public B, public C
{
public:
int _d;
int _D = 20;
};
int main()
{
D d;
d.B::_a = 1;
d.C::_a = 2;
d._b = 3;
d._c = 4;
d._d = 5;
B b;
b._b = 5;
return 0;
}
分析:我们从上述图片中可以看出d对象中A类出现了两次,以及A中的a存在了数据二义性。
2、解决方法(使用虚继承的方式)
class A
{
public:
int _a;
int _A = 10;
};
//class B : public A
class B : virtual public A
{
public:
int _b;
};
// class C : public A
class C : virtual public A
{
public:
int _c;
};
class D : public B, public C
{
public:
int _d;
int _D = 20;
};
int main()
{
D d;
d.B::_a = 1;
d.C::_a = 2;
d._b = 3;
d._c = 4;
d._d = 5;
B b;
b._b = 5;
return 0;
}
分析:由图中我们可以看到A被单独拿出来了,这时候我们通过d.B::_a = 1,d.C::_a = 2其实访问的A也就只要一份了。那么B和C是如何访问到a呢?答:通过虚基表指针。虚基表里存放的就是其类到类A的相对偏移量。
3、扩展知识
通过上面的虚继承,我们B类的结构其实也发生了变化,如下:
普通继承:
虚继承:
这就很好的解释了前面继承中的切片问题。
B b;
D d;
b._a = 5;
d._a = 10;
B* ptr = &b;
ptr->_a++;
//指向D类
ptr = &d;
ptr->_a++;
指向b的时候会b中也会有自己的虚基表找到偏移量在对自身的值修改,指向d的时候一样。