剖析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++深入的理解,开发者可以更好地利用这些特性来设计健壮的系统。在实际应用中,虚拟继承的使用应当谨慎,以确保它不会引入不必要的复杂性。

在这里插入图片描述

相关推荐

  1. C++——虚继承菱形继承

    2024-04-04 18:16:03       32 阅读

最近更新

  1. TCP协议是安全的吗?

    2024-04-04 18:16:03       18 阅读
  2. 阿里云服务器执行yum,一直下载docker-ce-stable失败

    2024-04-04 18:16:03       19 阅读
  3. 【Python教程】压缩PDF文件大小

    2024-04-04 18:16:03       19 阅读
  4. 通过文章id递归查询所有评论(xml)

    2024-04-04 18:16:03       20 阅读

热门阅读

  1. 设计模式:装饰器模式

    2024-04-04 18:16:03       15 阅读
  2. 如何使用Numpy优化子矩阵运算

    2024-04-04 18:16:03       16 阅读
  3. 机器学习算法与应用

    2024-04-04 18:16:03       16 阅读
  4. Electron无边框自定义窗口拖动

    2024-04-04 18:16:03       15 阅读
  5. WebSocket 对于手游的意义

    2024-04-04 18:16:03       17 阅读
  6. 代码随想录算法训练营第三十六天|leetcode416题

    2024-04-04 18:16:03       15 阅读
  7. MYSQL

    MYSQL

    2024-04-04 18:16:03      12 阅读
  8. 给23年自己的一封信(一点学习心得)

    2024-04-04 18:16:03       15 阅读
  9. C语言 06 无符号数

    2024-04-04 18:16:03       13 阅读