虚继承是如何解决二义性和数据的冗余的

2 篇文章 0 订阅
文章详细解释了C++中的多继承概念,通过一个类可以继承多个父类的例子,引出了可能存在的二义性问题。接着介绍了虚继承的作用,即解决命名冲突和数据冗余,通过内存布局展示了虚继承如何确保只有一份基类成员。文章通过实例代码和内存分析,说明了虚继承时的偏移量如何帮助定位基类成员,以及在多层继承结构中的应用。
摘要由CSDN通过智能技术生成

我们知道面向对象的三大特性分别为封装,继承,多态。在继承中,我们知道一个类可以继承另一个类,这样的关系被叫做子类(派生类)继承父类(基类),并且子类可以使用到父类的接口。但是在C++中还被设计了一个多继承,是什么意思呢。指的就是一个类可以继承多个类,就好比一个人可能他在这个学校担任老师,但是在另一边他可能是某个资历更深老师的某个学生,这样也产生了,如果一个老师类里面有名称了,学生里面也有一个名称,不可能他担任老师的时候叫做张三,担任学生的时候又叫做王五了。这里也就是二义性。但是我们可以通过对数据的指定性来解决二义性的问题,例如写下这样一段代码

 代码中写到,B继承了A,C继承了A,D继承了B,C,且作为基类中的A有一个_a的成员变量。可以大致把他们理解为这样的关系

 

 这就是一个菱形继承。接下来我们通过内存去看它们 

 通过对d的取地址观察我们可以看到确实是解决了数据二义性,但是数据的冗余是如何去处理的呢。这里我们可以用到一个虚继承,虚继承主要解决的就是命名冲突和数据冗余的问题,只保留一份基类的成员,关键字是virtual。当我们把关键字加上去之后再去对d取地址看到的内容就是这样的

 

 

 当把虚继承关键字加上去再去观察内存的时候明显发现,此时B,C类中原本为A的数据区被写道了最后一个位置,而原本的位置变成了一个地址,如果我们通过地址找过去看看又会发现什么

 

 通过地址过去之后发现第一个数据是00 00 00 00是因为它需要给其它的值预留空间,但是第二个值分别是十六进制的14,0c,对应的也就是十进制的20,和12。但是这两个值能代表什么呢。如果我们对比一下就能发现,从地址开始,B便宜20字节之后刚好是到A类,而C类偏移12字节后也恰好是到A类。

那么这个偏移量是用来干什么的呢。我们拿这样一段代码来举例。

在没有使用虚继承之前它的存储方式会是这样 

但是当使用了虚继承之后它的模型也会跟着发生变化

 

 可以看到b对象的模型也跟着发生了变化,也是一个指针指向一块区域,区域内存放着偏移量。

此时,我们利用B类定义一个对象,然后在用B类定义一个指针,让指针指向这个对象并且对对象中的_a进行操作,然后在让这个指针指向对象d,同样对d对象中的_a进行操作,那么此时的指针是无法知道具体指向谁的,它可能指向b对象,也可能指向d对象,所以这是就会利用偏移量,加上偏移量的值之后无论是b还是d都可以找到_a。

 当我们从反汇编的角度来看它的时候,也可以看到它是先利用当前的地址去加上偏移量来找到_a

 

 可能会有疑惑,为什么不能把地址直接存在对象里面,却偏偏要弄一个地址出来去存到那里,因为是要考虑到如果里面有多个值的情况,一个值就要一个地址,多个值就会造成对象空间的变大,所以会用一个指针来维护,管理一块区域。我们可以通过多加一个对象来观察确定。

 

  • 6
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值