c++对象内存模型 小记------vs附带查看器

cl [source.cpp] /d1reportSingleClassLayout[classname] 编译选项

示例:cl Test.cpp /d1reportSingleClassLayoutDerived

其中注意一点,继承中有时会出现一个奇怪的全零字段:vtordisp for vbase ..

以下是解释,直接连接自博客园:http://www.cnblogs.com/fanzhidongyzby/archive/2013/01/14/2860015.html

关于vtordisp知多少?

我相信不少人看到这篇文章,多半是来自于对标题中“vtordisp”的好奇。其实这个关键词也是来源于我最近查看对象模型的时候偶然发现的。我是一个喜欢深究问题根源的人(有点牛角尖吧),所以当我第一次发现vtordisp的时候,我也是很自然的把它输进google查找相关资料,但是结果令我不太满意。不过,即使如此,我还是把与它相关的资料整理如下,并结合自己的理解和大家分享一下,希望能共同学习进步。

首先从产生“vtordisp”问题的那个例子开始。

复制代码
class Base
{
public:
     int  base;
     virtual  void fun(){}
};
class Der: virtual  public Base
{
     int der;
public:
    Der(){}
     virtual  void fun(){}
};
复制代码

Der对象模型如下:

复制代码
1>   class Der    size( 20):
1>      +---
1>    0    | {vbptr}
1>    4    | der
1>      +---
1>   8    | (vtordisp  for vbase Base)
1>      +--- ( virtual  base Base)
1>   12    | {vfptr}
1>   16    |  base
1>      +---
1>  
1>  Der::$vbtable@:
1>    0    |  0
1>    1    |  12 (Derd(Der+ 0)Base)
1>  
1>  Der::$vftable@:
1>      | - 12
1>    0    | &(vtordisp) Der::fun
1>  
1>  Der::fun  this adjustor:  12
1>  
1>  vbi:        class  offset o.vbptr  o.vbte fVtorDisp
1>              Base       12        0        4  1
复制代码

我们发现对象的8字节偏移处,使用了4个字节存储了虚基类Basevtordisp。在我的前一篇博客内,我们并未涉及这个内容。首先,我从查阅一下vtordispMSDN的解释MSDN给出的解释是:虚继承中派生类重写了基类的虚函数,并且在构造函数或者析构函数中使用指向基类的指针调用了该函数,编译器会为虚基类添加vtordisp

然而,经过VS2010的测试,我们发现上述示例代码便会产生vtordisp字段!条件是。

1. 派生类重写了虚基类的虚函数。

2. 派生类定义了构造函数或者析构函数。

这两个条件缺一不可,这个结论与这里的描述是一致的。

但是,到目前为止,我们只是确定了vtordisp的产生条件而已。它究竟为什么存在对象的模型中,对象如何使用它(可能的解释),我们仍一无所知!

按照前边的资料内容,这个字段和编译选项/vd相关。/vd被称为构造置换(具体什么意思,我也不太清楚,惭愧!),它所解决的问题是:由于对类的虚拟基的置换与对其派生类的置换之间有差异,可能会向虚函数传递错误的 this 指针。 该解决方案向类的各个虚拟基提供称作 vtordisp 字段的单个构造置换调整。但是如何构造产生错误this指针的测试用例,请恕作者才疏学浅不能给出,也希望看到此文的大牛们给出测试用例。

另外,编译器还提供了预编译命令关闭vtordisp字段的产生。

#pragma vtordisp({on|off})

在我们刚才代码的前段关闭该字段的产生,事实证明也不会产生预期的错误,这的确匪夷所思,园子内另一篇博客下的评论也表达了同样的意思。而且,更重要的是,这个预编译命令一直说会在未来的VC版本内取消,但是我在VS2010下还是看到了它的身影。最后,我在一篇描述C++代理的文章中找到了另外一些线索。按照它的描述,这个字段一直存储为0。为了证明该猜测,我们用Der构造一个对象der,并查看该对象的内存内容。 

参考对象模型,该对象vtordisp的位置的确存储的是0

曾经我遇到过一个虚拟继承的实例,在对象的初始化过程中会修改vtordisp字段,但是每次在初始化结束前都会把vtordisp减去一个常量使得它的最终结果为0。而且没有出现任何访问该字段的汇编指令!(既然不访问,为何浪费指令设置它的值呢?)因此,这也让我怀疑编译器设计vtordisp的合理性。

无论如何,我们发现对编译器产生的vtordisp字段了解的是太少了。单纯依靠代码动作猜测该字段存在的含义可行性十分有限,希望对此内容清楚的园友能给出合理的解释。




  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

failwest9527

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值