虚继承解决菱形继承的原理

菱形继承的问题,是由多重继承的父类祖先是同一个父类导致的。如下面的情况:

菱形继承,会导致同名成员的二义性问题和数据冗余问题,用下面的代码来测试:

class A
{
public:
	int _a;
};
// class B : public A
class B : public A
{
public:
	int _b;
};
// class C : public A
class C : public A
{
public:
	int _c;
};
class D : public B, public C
{
public:
	int _d;
};
int main()
{
	D d;
	d.B::_a = 1;	
	d.C::_a = 2;
	d._b = 3;
	d._c = 4;
	d._d = 5;
	return 0;
}

当菱形继承不加处理的话。会导致下面的情况:同名成员的二义性问题

这种二义性问题,用下面的方式即可解决:指定类域

但是还会有下面的数据冗余问题:如下,成员 _a 占据了两份同样大空间(01和02那块内存地址) ,定义成员 d时,分别对 B和C开了一块空间,而B和C又要继承类A,所以B和C都对 _a 这个成员开了一样的空间。

当_a成员不是很大的时候,还好,但当有一群_a这样的同名成员的时候,内存开销就太大了!

虚继承解决了这个问题,它是怎么解决的呢?

用上面的 A,B,C,D类来举例子。当定义出一个D的对象 d 的时候,D中继承了成员 B和 C 的各自的成员变量_b和_c,也通过 B和 C继承了 A 的成员 _a,虚拟继承会将 _a 放在一个公共的区域,通过B和C中指针指向的一张表。这两个指针叫虚基表指针,这两个表叫虚基表。虚基表中存的偏移量。通过偏移量可以找到下面的A。

如成员 _b 前面的指针,指向的虚基表里存的 16进制的14,代表 20 个字节,这恰好是_b前面的指针起始位置距离 _a 的距离,知道这个距离后,访问的时候就能找到 _a 的位置了。

再如 _c 前面的指针,指向的虚基表里的 0c ,表示十进制的 12,这个指针的起始位置和 _a 的距离就是 12,访问的时候即可以找到了。

综上所述,在虚拟继承的时候,可以通过两个类里各自指针指向虚基表里的偏移量来计算同名成员的位置,并且内存位置是相同的,这也符合我们的认知。

虽然菱形继承有了虚拟继承来解决问题,但它的底层极其复杂,会对性能造成极大影响!

所以,虽然能解决,但尽量不要设计出菱形继承!!

  • 9
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值