剖析C++中的菱形继承

剖析C++中的菱形继承

前言

在面向对象编程中,继承允许我们构建出复杂的类关系和对象模型。然而,当多个类继承自同一个基类时,可能会引发结构上的冲突和数据冗余。这种情况在C++中被称为菱形继承。本文通过实例代码和内存监视图解析了菱形继承的问题,并介绍了虚拟继承作为一种解决方案。


菱形继承

首先给出一段便于我们测试的菱形继承代码:

class A
{
public:
	int _a;
};

class B : public A
{
public:
	int _b;
};

class C : public A
{
public:
	int _c;
};

class D : public B, public C
{
public:
	int _d;
};

接着我们为了便于通过调试窗口观察各个类中成员的分布情况,相应的给出如下测试代码:

void test()
{
	A a;
	B b;
	C c;
	D d;

	a._a = 1;

	b._b = 2;
	b._a = 22;

	c._c = 3;
	c._a = 33;

	d._d = 4;

	d.B::_a = 5;
	d.C::_a = 6;

	cout << sizeof(a) << endl;
	cout << sizeof(b) << endl;
	cout << sizeof(c) << endl;
	cout << sizeof(d) << endl;
}

调试窗口:

在这里插入图片描述

监视内存窗口截图:
在这里插入图片描述

通过上面的内存窗口我们可以看到数据冗余,D类实例化出的对象d拥有两个分别归属于B和C的成员变量_a,为了解决这种冗余问题,我们引出了菱形虚拟继承,下面将会接着分析虚拟继承的特性:

虚拟继承与虚基表

首先我们对代码稍作修改,将A类与B、C类之间的继承关系变为虚继承:

class A
{
public:
	int _a;
};

//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;
};

测试代码基本保持不变:

void test()
{
	A a;
	B b;
	C c;
	D d;

	a._a = 1;

	b._b = 2;
	b._a = 22;

	c._c = 3;
	c._a = 33;

	d._d = 4;
	d._b = 44;
	d._c = 55;

	d.B::_a = 5;
	d.C::_a = 6;

	cout << sizeof(a) << endl;
	cout << sizeof(b) << endl;
	cout << sizeof(c) << endl;
	cout << sizeof(d) << endl;
}

监视内存窗口:

在这里插入图片描述

通过上面分析图可以得出D对象中将A放到的了对象组成的最下面,这个A同时属于B和C,那么B和C如何去找到公共的A呢?这里是通过了B和C的两个指针,指向的一张表。这两个指针叫虚基表指针,这两个表叫虚基表。虚基表中存的偏移量,通过偏移量可以找到下面的A。

运行窗口:

在这里插入图片描述

我们看到经过虚继承的B、C类都要比之前更大,因为内部多存放了一个虚基表指针,指向用来存放类虚继承下来的成员变量的虚基表。

在虚拟继承的情况下,虚基表指针(vptr)和虚基表(vtable)的引入,确保了基类A的唯一性。这种机制允许B和C类通过虚基表指针找到共享的基类A实例。虽然这增加了一些内存开销,但它解决了数据冗余的问题,并保证了类层次中数据的一致性。


总结

​ 虚拟继承是C++中处理菱形继承问题的关键。通过将基类声明为虚基类,我们可以确保在派生类中只有一个基类实例,从而避免了数据冗余。这种方法虽然在内存布局上稍显复杂,但它提供了一种在复杂类层次中保持数据一致性的有效方式。随着对C++深入的理解,开发者可以更好地利用这些特性来设计健壮的系统。在实际应用中,虚拟继承的使用应当谨慎,以确保它不会引入不必要的复杂性。

在这里插入图片描述

  • 5
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

螺蛳粉只吃炸蛋的走风

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值