21(3).菱形继承(钻石继承) 引入虚拟继承

菱形继承(钻石继承)

  • 虚拟继承virtual
//菱形继承(钻石继承) wrong example
class Base
{
public:
	int base_data;
};

class A : virtual public Base
{
public:
	int a_data;
};

class B : virtual public Base
{
public:
	int b_data;
};

class D :public A, public B  //多继承
{
public:
	int d_data;
};

void main()
{
	cout<<sizeof(D)<<endl;
	D d;
	d.a_data = 1;
	d.b_data = 2;
	d.d_data = 3;
	d.A::base_data = 5;
	d.B::base_data = 6;
	d.base_data = 0;
    cout << "sizeof(d) is " << sizeof(d) << endl;  //24
	cout<<&(d.A::base_data)<<endl;
	cout<<&(d.B::base_data)<<endl;
}

以上代码是无法编译过的,但是当屏蔽掉: d.base_data = 0;这一行代码之后,程序就能正常执行了,调试后发现,派生类对象d去访问基类的基类公有数据成员时,就会产生二义性问题,派生类D的直接基类时A和B,A和B都公有继承了base类,相当于A和B中都各自有一个隐藏的base类,然后D继承A和B,D中便有隐藏的A和D,而A和D都有一个隐藏的base类,于是D中就有两个base,通过D去访问base的数据成员便会产生二义性问题
.d的大小时20个字节,d的数据成员d_data占4,其中隐藏的A和B对象各占8,其中4是数据成员,其中4是vbptr( virtual base-table pointer )
虚拟继承可以解决菱形继承的二义性和数据冗余的问题。如上面的继承关系,使用虚拟继承,即可解决问题。需要注意的是,虚拟继承不要在其他地方去使用。

菱形继承(会产生二义性)

菱形继承(加了virtual关键字后不再二义性)

//菱形继承(钻石继承) right example
class Base
{
public:
	int base_data;
};

class A : virtual public Base
{
public:
	int a_data;
};

class B : virtual public Base
{
public:
	int b_data;
};

class D :public A, public B  //多继承
{
public:
	int d_data;
};

void main()
{
	cout<<sizeof(D)<<endl;
	D d;
	d.a_data = 1;
	d.b_data = 2;
	d.d_data = 3;
	d.A::base_data = 5;
	d.B::base_data = 6;
	d.base_data = 0;
	cout << "sizeof(d) is "<< sizeof(d) << endl;  //24
	cout<<&(d.A::base_data)<<endl;
	cout<<&(d.B::base_data)<<endl;
}

数据实际还是两份的,只不过是,在整个d对象内存的后面增加了一个基类Base的数据成员,然后通过虚基表虚拟映射过去的,造成无论通过A还是B去访问base_data都是一个值的假象,如下图:

在这里插入图片描述

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值