深度探索C++对象模型之Data语义学小测试

为了加深对虚拟继承中派生类对象的成员分布关系,测试了一下书本里的example,对于不使用虚拟继承的对象在成员分布上就比较简单,即使是多重继承对应的直接基类子对象也是完整的,基类指针指向派生类对象(现在知道严格来说是指向派生类的对应基类部分)只需要加上相应偏移即可,不需要加入新的指针结构增加一层中间逻辑,而虚拟继承中会引入不变局部和可变局部部分,都是将虚基类对象部分独立出来,每个子对象部分用指针指向或者使用偏移表;


#include "stdafx.h"

#include "assert.h"
class point2d
{
public:
private:
float _x, _y;
};


class vertex:public virtual point2d
{
public:
private:
vertex *next;
};


class point3d:public virtual point2d
{
public:
private:
float _z;
};


class vertex3d: public vertex, public point3d
{
public:
private:
float mumble;
};


int _tmain(int argc, _TCHAR* argv[])
{
vertex3d *pv3d = new vertex3d;
point3d *p3d = pv3d;
vertex *pv = pv3d;
point2d *p2d1 = pv3d;
point2d *p2d2 = p3d;
point2d *p2d3 = pv;
assert(p2d1 == p2d2 && p2d2 == p2d3);


return 0;

}


测试结果和教材P123完全一致, 说明VC采用的是此 Virtual Table Offset Strategy模式

pv3d = 00140B28

pv = 00140B28   Vertex Subobject位于最其实的部分,不过此时从基类继承过来的对象部分变成了指针(或偏移)串联的,而不是连续的整体
p3d = 00140B30            相差8个字节,刚好是Vertex subobject占的8个字节 Vertex* next 与 __vptr__Vertex
p2d = 00140B3C         抽象基类部分离起始位置20字节 8+8 +4(自身成员 mumble)


各子对象所占空间

sizeof(vertex) = 16
sizeof(point3d) = 16
sizeof(point2d) = 8
sizeof(vertex3d) = 28

与教材中的布局还是契合的,注意这里没有虚函数所以point2d vertex  point3d都没有vptr比书本上少了4字节,但是没有共有的vptr共享对象指针还是需要额外分配的,这样就满足了上述分布关系了;


有意思的是将两条派生路径中的虚拟继承属性其中一条改为普通继承(譬如point3d),这样在最高层派生对象vertex3d中会有两个完全不同的point2d子对象,一个是偏移指示+独立共享子对象的结构vertex还是虚基类的布局,这样绑定point2d基类对象就会出现歧义了 因为存在两种方式读取独立的两个子对象(而不是所有的路径都是虚 带上指针,所以virtual属性更像是修饰基类而不是继承关系,以基类为中心就不会遗漏路径),果不其然,编译器会报错:  error C2594: “初始化”: 从“vertex3d *”到“point2d *”的转换不明确 


将两个virtual属性都去除的话更容易理解:对象中有两个常规意义上的point2d副本,编译器无法判定该给用户绑定哪一个,给出同上的报错信息(但是里面的布局是不一样的);唯一的方法是将指针转型为其直接上层(选择信息)

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值