zoukankan      html  css  js  c++  java
  • vtordisp

    关于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字段了解的是太少了。单纯依靠代码动作猜测该字段存在的含义可行性十分有限,希望对此内容清楚的园友能给出合理的解释。

    作者:Florian
    本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。[若本文对你有所帮助,还望多多推荐支持~!]
     
    分类: C++
    标签: vtordisp
  • 相关阅读:
    外校培训前三节课知识集合纲要(我才不会告诉你我前两节只是单纯的忘了)
    floyd算法----牛栏
    bfs开始--马的遍历
    (DP 线性DP 递推) leetcode 64. Minimum Path Sum
    (DP 线性DP 递推) leetcode 63. Unique Paths II
    (DP 线性DP 递推) leetcode 62. Unique Paths
    (DP 背包) leetcode 198. House Robber
    (贪心 复习) leetcode 1007. Minimum Domino Rotations For Equal Row
    (贪心) leetcode 452. Minimum Number of Arrows to Burst Balloons
    (字符串 栈) leetcode 921. Minimum Add to Make Parentheses Valid
  • 原文地址:https://www.cnblogs.com/Leo_wl/p/2860086.html
Copyright © 2011-2022 走看看