关于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个字节存储了虚基类Base的vtordisp。在我的前一篇博客内,我们并未涉及这个内容。首先,我从查阅一下vtordisp的MSDN的解释。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字段了解的是太少了。单纯依靠代码动作猜测该字段存在的含义可行性十分有限,希望对此内容清楚的园友能给出合理的解释。

C++虚继承(一) --- vtordisp字段相关推荐

  1. C++ 多继承和虚继承的内存布局

    原文链接:https://www.oschina.net/translate/cpp-virtual-inheritance 警告. 本文有点技术难度,需要读者了解C++和一些汇编语言知识. 在本文中 ...

  2. C++之虚函数与虚继承详解

    虚继承和虚函数是完全无相关的两个概念. 虚继承是解决C++多重继承问题的一种手段,从不同途径继承来的同一基类,会在子类中存在多份拷贝.这将存在两个问题: 其一,浪费存储空间: 第二,存在二义性问题,通 ...

  3. 一个虚函数和虚继承的问题。

    这个问题困惑好几天了.废话不多说,先上代码. 1 #include <iostream> 2 using namespace std; 3 4 class A 5 { 6 public: ...

  4. 多重继承和虚继承的内存布局

    这篇文章主要讲解虚继承的C++对象内存分布问题,从中也引出了dynamic_cast和static_cast本质区别.虚函数表的格式等一些大部分C++程序员都似是而非的概念.原文见这里 (By Eds ...

  5. C++中的虚继承与虚基类

    1.Cpp中的虚继承与虚基类 在多继承时,很容易产生命名冲突的问题,即使我们很小心地将所有类中的成员变量和成员函数都命名为不同的名字,命名冲突依然有可能发生,比如典型的是菱形继承,如下图所示: 类A派 ...

  6. 钻石问题(菱形继承问题) 和虚继承

    在C++中,什么叫做钻石问题(也可以叫菱形继承问题),怎么避免它? 下面的图表可以用来解释钻石问题. 假设我们有类B和类C,它们都继承了相同的类A.另外我们还有类D,类D通过多重继承机制继承了类B和类 ...

  7. C++对象模型6——g++中虚继承的实现

    虚基类的实现法在不同编译器之间差异极大.然而,每一种实现法的共同点在于必须能够在执行期准确描述虚基类在其每一个派生类中的位置. 一.虚继承的实现 struct A {int ax;virtual vo ...

  8. C++知识点53——虚继承

    二.虚继承 1.概念 默认情况下,C++的派生列表中不允许同一个基类出现两次,但是,如果两个基类都继承了同一个类A,那么两个基类派生出的子类就会包含两次类A的部分 为了解决上述问题,C++中就出现了虚 ...

  9. 关于虚继承(在钻石继承体系中,一定要用虚继承!)

    在钻石继承体系中,一定要用虚继承! 1.下面的代码块儿无法通过编译,原因是,A3无法确定自己到底是用哪一个父类中的函数. class A { public: virtual void f(){} vi ...

最新文章

  1. 学习《Linux设备模型浅析之驱动篇》笔记(一)
  2. java mvc数据库 封装_Springmvc对就jdbc封装的操作
  3. h5新增的属性php,HTML5中form的新增属性或元素
  4. 【CodeForces - 701D】As Fast As Possible(二分,模拟,数学公式)
  5. 图【数据结构F笔记】
  6. MySQL单机版Recycle Bin回收站功能
  7. Google Map二次开发——API方式
  8. 性能指标、响应时间、并发量…聊聊性能优化的衡量指标
  9. eslint的安装与使用
  10. aix创建oracle表空间,Oracle for AIX基于裸设备的表空间扩充步聚
  11. 工作学习总结--ng2-pdf-viewer的运用
  12. Adapter(适配器)模式
  13. 蒋文华《博弈论》笔记及视频摘录
  14. USB Host、USB Device和USB otg的理论简析
  15. 使用Kettle从国家统计局下载行政区划代码数据
  16. win7适合oracle哪个版本下载,win7系统下载--Windows 7下成功安装ORACLE客户端
  17. mysql查询最新的一条记录_mysql 查询不同用户 最新的一条记录
  18. 适合空间受限能量收集应用的高度集成电源 IC
  19. WIN8软件测试,win8实测!!!测试常用软件。
  20. 地图位置签到打卡线上线下结合活动的小程序 document.getElementById(‘demo‘)

热门文章

  1. aop实现原理-动态代理CGLib代理
  2. win32 输出文字时清除之前的_努力学习没效果?3个步骤,强化沟通输出,实现飞跃式成长...
  3. Allegro光绘的导出
  4. DESIGN_OUTLINE' and 'CUTOUT' are the preferred subclasWARNING
  5. vue mixins
  6. 微信小程序------MD5加密(支持中文和不支持中文)和网络请求(get和post)
  7. 固特异发布人工智能球形轮胎:自动变形、自我修复、超级灵活
  8. day1---python的基础特性
  9. HAProxy + Keepalived + Flume 构建高性能高可用分布式日志系统
  10. 提高网站的性能----回流与重绘