虚继承的对象分布/C++

本文探讨了C++中的虚继承问题,解释了如何通过虚继承避免对象复制,并分析了编译器底层实现。内容包括多重继承、编译器如何处理虚基类对象的存储,以及不同编译器的解决策略,强调了虚继承可能导致的效率问题和有效使用场景。
摘要由CSDN通过智能技术生成

首先,让我们来引入话题

1. 多重继承

考虑以下情况,在这里插入图片描述

base class中对象可能会被derived class重复复制,为解决此问题,C++引入virtual inheritance(虚继承)在这里插入图片描述
图为虚继承后的iostream继承体系图。

// 此处并非是iostream库的标准实现,只是为了方便理解
class ios {...};
class istream : public virtual ios {...};
class ostream : public virtual ios {...};
class iostream : public istream,public istream {...};

2.考虑编译器底层实现:

  1. 将原本istream和ostream各自维护的一个ios子对象, 转为由iostream维护的单一ios子对象
  2. 保存base class和derived class的指针之间的多态操作。

一般的实现方法:class中如果内含一个或多个virtual base class subobjects,将被分割为不变区域和共享区域。
其中,不变区域有固定的offset,共享区域则因为每次派生操作有变化。
一般的布局策略:先安排好derived class的不变部分,再建立共享部分。

cfront实现(cfront是早期的C++编译器)
在每个derived class object中存放指针,每个指针指向其virtual base class

考虑一下几个类
在这里插入图片描述
考虑为我们的Point3d重载+=运算符

// 
void Point3d::operator(const Point3d & rhs){
	_x+=rhs._x;
	_y+=rhs._y;
	_z+=rhs._z;
}

cfront下,内部实现为

//虚拟C++代码,vbc指的是virtual base class
_vbcPoint2d->x += rhs._vbcPoint2d->x;
_vbcPoint2d->y += rhs._vbcPoint2d->y;
_z += rhs._z;

derived class 和 base class之间的转换

Point2d * p2d = pv3d;

在cfront实现下,为

//虚拟C++代码
Point2d * p2d = pv3d? pv3d->_vbcPoint2d : 0;

注:当pv3d为nullptr时, p2d会被直接赋值为空指针。

思考这样做的缺点:

  1. 当一个class object 的virtual base class 个数增长时,每个class object的size会很大。
  2. 虚继承链的加长,会使得间接存取层次增加,从而影响效率。(设想我们要访问基类对象,而class object的指针指向了virtual base class ,而此virtual base class也有指向上层virtual base class的指针)(类似套娃?)

3.一些编译器的解决方法

问题1的解决方法:
1.Microsoft 在class object里存放指针,指向virtual base class table。
2.在virtual function table 中放置virtual base class的offset
在这里插入图片描述

但是转换操作

Point2d * p2d =pv3d;

变为

Point2d * p2d =pv3d ? pv3d+pv3d->_vptr_Point3d[-1] : 0;

我们发现利用虚函数指针即可完成所需转换,解决了问题1。

再回头考虑问题2,这样的模型实现之后,对于继承而来的对象做存取,依然难免会遇到存取层次的增加。
但是经由非多态class object来存取继承而来的对象

Point3d p3d;
p3d._x;

编译器就可以直接优化为存取操作,可以在编译时期被决议。(offset已经被提前预知)

virtual base class最有效的运用:抽象的virtual base class作为接口类,没有任何data members。
Multiple inheritance does have legitimate uses. One scenario involves combining public inheritance from an Interface class with
private inheritance from a class that helps with implementation.–《Effective C++》
第一次写技术博客,可能有一些错误,希望读者能指出,谢谢。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值