C++:类和对象:继承:虚继承详解

本文深入探讨了C++中的虚继承概念,通过案例分析了非虚继承与虚继承的区别,指出虚继承能够解决多继承时的冗余问题和成员访问不明确的困境。文章介绍了虚继承的底层原理,包括虚基表指针和偏移量的作用,并通过调试展示了虚继承如何找到父类数据。同时,强调了正确使用虚继承的注意事项,即虚继承仅在多继承场景下有意义,确保间接子类对公共父类的唯一引用。
摘要由CSDN通过智能技术生成

上一篇文章,我大概说了下:虚继承概念。

C++:类和对象:继承_hongwen_yul的博客-CSDN博客

这篇问题,我们重点分析虚继承底层原理。

C++语法——详解虚继承_就要 宅在家的博客-CSDN博客_c++ 虚继承

案例:假设有如下代码

#include<string>
#include<iostream>
using namespace std;
class A {
public:
	int a;
};

class B :virtual public A {
public:
	int b;
};
class C :virtual public A {
public:
	int c;
};
class D :public B, public C {
public:
	int d;
};

int main() {
	D d;
	d.a = 1;
	d.b = 2;
	d.c = 3;
	d.d = 4;
	return 0;
}

 1:先看图(如果上述代码不采用虚继承)

 此时可以看到D类实例化对象内部结构如图所示

很显然 至少面临两个问题

1:基类A中的 成员变量 int a , 在子类B和子类C中各自存在一份,这显然是冗余的

2:基类D在调用基类变量 a时(D::a),还会提示:D::a 不明确(这里不明确的意思就是不知道调用子类B的还是调用子类C的)

2:修改成虚继承模式

 

 显然通过虚继承,很好的解决了上面两个问题。

 3:虚继承原理

在上图中,父类数据并不存放在 虚继承的子类中,那么子类是怎么找到父类的数据的了?

1:在虚继承的类中,会定义一个虚基表指针vbptr ,这个指针指向虚基表

2:在虚基表中存在偏移量,这个亮就是表的地址到 父类数据地址的距离,通过这个距离,子类就可以找到唯一的  成员。

4:通过调试来分析 

先查看对象d的 内存分布

 上图我们引出了 虚基表指针

现在我们再通过内存窗口,查看一下虚基表指针指向的地址。

 这就解释了,为什么 bptr 和 cptr (虚基表指针)能找到并不位于自己内部的变量a ?

因为通过 bptr和cptr 去寻找 变量a 时,会从自身的虚基表指针中找到虚基表,通过虚基表保存的偏移量就可以找到变量a 地址,从而找到变量a。

简化下就是下图

5:使用虚继承需要注意的事情 

当使用虚继承的时候,需要注意,虚继承只有在多继承时才有用,也就是说如果只有一层继承关系或者是单继承都将不起作用。

因为虚继承时保证子类中只有一个间接父类,即虚继承只能在隔代继承中起作用。

比如:下面这两种情况即便使用虚继承也是没意义的。

 第一种情况:虽然 class B虚继承产生了 虚基表和指针,但是 class B并 没有子类,而虚继承是用以保证子类只有一个间接父类 class A 。而本例 class B 并没有子类。

第二种情况:Class C虚继承了 Class B,但是 class B是 class A的非继承类,那么class B 就存在一份 A 。 Class D 对A 是虚继承(保存指向A的虚基表),这就导致 class E 在实例化时存存放一个 对D而言公共的 A 。 这样导致 class E 中还是存放两个 A ,那么调用变量就会出现混乱。

所以正确的继承关系应该是:当 Class A的子类继承它时,应该都定义成虚继承,这样才能保证当有像 Class  E 这样的间接子类定义时,成员才会在公共区域只有一份。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值