哈哈,从M$ Visual C++ Team的Andy Rich那里又偷学到一招:VC8的隐含编译项/d1reportSingleClassLayout/d1reportAllClassLayout 。看个复杂的例子吧(如下),现在假设我们想知道Derived类的对象布局,怎么办? 在Project Properties->C++->Command Line->Additional Options里面加上/d1reportSingleClassLayoutDerived吧!

;

}

F5编译之,你会惊奇地发现,Output里面有如下字样:


到了吗? VC8居然输出了Derived对象的完整布局!
我们终于可以不必两眼一抹黑般的去peek/poke了....第1行表明,Derived对象总占用了32字节;其由三部分组成,分别是行3-行7、行
8-行12、行13、行28;其中前二者分别是基类Base1、Base2的布局,最后的行28为虚拟基类Common的布局。

以基类
Base1部分为例,可发现其由一个虚函数表指针vftable和虚基表指针vbtable构成,先看Base1部分的vftable所指向的虚
表$vftable@Base1(行19),不难发现,其中的表项2已经被Derived::print2给override了;再来看Base2部分的
vftable所指向的虚表$vftable@Base2(行23),可发现,同样的,Base2::dump2被Derived::dump2给
override了。这不明摆着就是虚函数机制嘛,heh~

值得注意的是,这个例子同时说明,多继承场合下,其实在单一对象中是存在多个
this指针的....行35-36给出了如何将Derived的this指针校正为其基类子对象this指针的偏移量,也就是说,根据行36,假设有个
Derived
d,那么d.dump1()实际上应该理解成通过虚表$vftable@Base2对((Base2*)
(((char*)&d)+12))->dump1()的调用....即传递给所有Base2成员函数的this指针应该是
(Base2*)((char*)(&d)+12),这里可能我写得恐怖了点,意思到了就成....这不,普通继承、多继承、对象Slicing
的语义都在这个布局里面了,看仔细了哈~

OK,多继承看完了,继续看虚拟基类是如何布局的。虚基Common在Derived的布局中,
位于Derived本身数据成员之后的位置。Base1、Base2中均保存了一个vbtable指针,其分别指向各自所使用的虚基
表$vbtable@Base1和$vbtable@Base2,为什么要指向一个虚基表?
很简单,因为Base1、Base2有可能会同时继承多个不同的虚拟基类.....这充分体现了C++对象布局的复杂性....在每个虚基表中,保存了所
继承的虚拟基类部分相对于子类部分vbtable指针的偏移值,以Base2为例,我们知道Base2的vbtable在Derived中的偏移值为
16(行10),则根据$vbtable@Base2,虚基Common部分距离Base2
vbtable指针的偏移值为12,则有虚基Common在Derived中的总偏移值为16+12。与普通多继承同理,我们在调用非虚拟的虚基成员函数
时,必须将Derived的this指针调整为指向虚基部分的this指针,只有这样才能成功地访问虚基自身的数据成员和虚基的虚拟函数(通过虚基自己的
vftable,为简单起见,上例中我就没弄那么复杂了,大家可以自己玩玩,明白如何举一反三即可)

看完了上述解释,是不是感觉比啃Inside C++ Object Model来得更快更直观啊?heh

Visual C++ 8.0对象布局的更多相关文章

  1. Visual C++ 8.0对象布局的奥秘:虚函数、多继承、虚拟继承(VC直接输出内存布局)

    原文:VC8_Object_Layout_Secret.html 哈哈,从M$ Visual C++ Team的Andy Rich那里又偷学到一招:VC8的隐含编译项/d1reportSingleCl ...

  2. visual studio2013 C++查看对象布局

    一在visual studio中进行设置,可以方便的查看对象的内存布局 右键所要显示的*.cpp >> 属性 >> 命令行 >> 其它选项 在其他选项中添加: /d ...

  3. VC++对象布局的奥秘:虚函数、多继承、虚拟继承

    哈哈,从M$ Visual C++ Team的Andy Rich那里又偷学到一招:VC8的隐含编译项/d1reportSingleClassLayout和/d1reportAllClassLayout ...

  4. Xamarin For Visual Studio 3.0.54.0 完整离线破解版(C# 开发Android、IOS工具 吾乐吧软件站分享)

    Xamarin For Visual Studio就是原本的Xamarin For Android 以及 Xamarin For iOS,最新版的已经把两个独立的插件合并为一个exe安装包了.为了区分 ...

  5. C++ 类继承的对象布局

    C++多重继承下,对象布局与编译器,是否为虚拟继承都有很大关系,下面将逐一分析其中的差别,相同点为都按照类继承的先后顺序布局(类内按照虚表.成员声明先后顺序排列).该类情况为子类按照继承顺序排列,如c ...

  6. 基于Visual C++6.0的DLL编程实现

    整理自基于Visual C++6.0的DLL编程实现 本文通过通俗易懂的方式,全面介绍了动态链接库的概念.动态链接库的创建和动态链接库的链接,并给出个简单明了的例子,相信读者看了本文后,能够创建自己的 ...

  7. Xamarin For Visual Studio 3.0.54.0 完整离线破解版

    Xamarin For Visual Studio 3.0.54.0 完整离线破解版 Xamarin For Visual Studio就是原本的Xamarin For Android 以及 Xama ...

  8. 转 Visual C++6.0 与matlab联合编程(2)----Visual C++6.0 环境下编译和调试MEX文件

    我的最初想法是利用matlab的mex命令调用C++程序生成动态链接库的,但是测试程序(文中另附)通过了,自己的实际应用程序却没有过.还是把方法贴在这儿,以便自己以后进行整理. http://shij ...

  9. win7+python3.6+word_cloud 安装出现Microsoft Visual C++ 14.0 is required

    说明 环境: 已安装Anaconda3 (64-bit) 4.4.0(Python 3.6.1).其中,代码调试在Spyder 3.1.4中进行,安装包则直接打开Anaconda Prompt调用cm ...

随机推荐

  1. urllib库使用方法 4 create headers

    import urllib.requestimport urllib.parse url = "https://www.baidu.com/"#普通请求方法response = u ...

  2. C语言不定型参数函数定义

    我们在C语言中定义一个函数,通常都是需要在函数原型中规定这个函数需要提供什么类型的参数以及需要提供多少个.也就是,你的参数必须明确.但是我们调用函数库中的printf和scanf函数会发现,它们似乎是 ...

  3. Go语言反射之值反射

    1 概述 反射不仅可以获取值的类型信息,还可操作变量的值.使用 reflect.Value 类型操作变量的值. 2 值反射对象 reflect.ValueOf() 方法可以获取一个值的反射对象,之后可 ...

  4. Linux入门进阶第五天——用户管理(帐号管理 )上

    一.帐号与群组 关于使用者帐号: 用户的ID与帐号信息所在位置是 /etc/passwd,而管理密码的数据则是在 /etc/shadow 每个登陆的使用者至少都会取得两个 ID , 一个是使用者 ID ...

  5. 20155310 《Java程序设计》实验三(敏捷开发与XP实践)实验报告

    20155310 <Java程序设计>实验三(敏捷开发与XP实践)实验报告 实验内容 1.XP基础 2.XP核心实践 3.相关工具 实验步骤 (一)敏捷开发与XP 1.敏捷开发 敏捷开发( ...

  6. 20155321 2016-2017-2《Java程序设计》课堂实践项目

    20155321 2016-2017-2<Java程序设计>课堂实践项目 关于String类 split方法 charAt方法 项目题目: 模拟实现Linux下Sort -t : -k 2 ...

  7. SublimeText 改变 tab的距离

    view -> Indentation -> Tab width ……

  8. BZOJ2140_稳定婚姻_KEY

    题目传送门 暴力直接对于每个点跑一遍二分图匹配,能拿四十分. 然而我们考虑正解. 对于一对Couple我们建♂->♀的一条边,对于一对曾经有恋情的情侣我们建♀->♂的一条边. 跑Tarja ...

  9. 【JUC源码解析】Semaphore

    简介 Semaphore(信号量),概念上讲,一个信号量持有一组许可(permits). 概述 线程可调用它的acquire()方法获取一个许可,不成功则阻塞:调用release()方法来归还一个许可 ...

  10. linux 命令缩写

    su super user apt advanced packaging tool ifconfig interface configuration so shared object fsp frac ...