大家看到标题,会不会菱形继承的虚表会不会是重复的呢?祖父类的虚表会不会在子类会不会是两份相同呢?那么我们一起来探索一下吧,冲冲冲!!



首先我们来分析一下:
它一共定义了四个类,分别为CFurniture,CSofa,CBed和CSofaBed。CFurniture为祖父类,从CFurniture类中派生了两个子类:CSofa与CBed,它们在继承时使用了virtual的方式,即虚继承。

接下来我们来看看CSofaBed的对象的内存结构图

那么这些数据都有什么含义呢?如下所示:

看了一下,大概能看懂,但是还有一个模糊不清的数据无法理解,就像CSofaBed_vt(new)和vt_offset,他们又代表什么东西呢?唉,只能去探索汇编代码,继续冲冲冲!!!



在这里解释一下地址40F732~40F742之间汇编代码的作用:

ebp-24h是对象的向后偏移四个字节的地址,因为ebp-28h是this指针,也就是对象的首地址,this值即内存图中的12FF58,所以[ebp-24h]也就是对象的第二个字节的数据,其实说白了它还是个地址,也就是12-13内存图中的第二行数据 425050,即[ebp-24h]的值是425050,然后放入ecx中,ecx+4也就是这个地址向后偏移 4个字节,即425054,然后[ecx+4]的值即为1C,这个值就是父类虚表指针相对于vt_offset的偏移,然后把这个值放入edx,作为一个偏移值,ebp-24h+edx 意思就是相对于第二个字节的偏移为1C的地址,[ebp-24h+edx]不就是这个地址的值了吗?也就是祖父类的首地址,即祖父类的虚表指针的地址

上面分析了一下汇编代码,分析出了vt_offset所指向的内存地址中保存的数据为偏移数据。如下图,图中每个vt_offset对应的数据有两项:第一项是-4,即vt_offset所属类对应的虚表指针相对于vt_offset的偏移值;第二项保存的是父类虚表指针相对于vt_offset的偏移值(上面已分析结束,至于第一项的话,大家看汇编代码都能看出)


根据上面我们找出的vt_offset是地址12FF5C,向下偏移1C的话,1C是多少个字节?刚开始我一直搞成12个字节?!!!!!我都搞不懂那个1被我想哪去了?!!!1C也就是 16+12=28个字节,也就是向下偏移7行,即到地址12FF78处,它的值为42501C,这也就是父类虚指针的地址。当然也可以用第二个来算,因为它俩的父类都是同一个,所以算出来的地址肯定也是42501C(快速算一下:也就是425044的地址是12FF68,然后向下偏移10h(16个字节)个字节,也就是4行,即12FF78处,值为42501C)

根据前面所述,这里有三个虚表指针:
0x425034(用0x12FF5C -0x4=0x12FF58,根据上面内存图此处地址的值为0x425034),0x425028(从汇编代码地址0x40F752分析得出)(至于0x12FF68如何得来,需要去分析汇编代码,用0x12FF68 -0x4=0x12FF64,根据上面内存图此处地址的值为0x425028),
0x42501C(已算出是祖父类起始地址)

所以总结如下:

vt_offset是一个地址,这个地址所指向的地方存在了两个偏移值,第一个值是当前类对应的虚表指针相对于vt_offset的偏移值,第二个值是父类对应的虚表指针相对于vt_offset的偏移值,每个虚继承类都有一个相应的vt_offset,可找到父类的虚表指针,也可找到自身类的虚表指针。


这三个虚表指针指向的虚表包含了子类CSofaBed含有的虚函数有了这些记录就可以随心所欲地将虚表指针转换成任意的父类指针。
在利用父类指针父类指针访问虚函数时,只能调用子类与父类共有的虚函数,子类继承自其它父类的虚函数是无法调用的,虚表中也没有相关记录。当子类的父类存在多个父类时,会在12-15所显示的表格中依次记录它们的偏移。

虚函数系列:
详解虚函数的实现过程之初探虚表(1)
详解虚函数的实现过程之单继承(2)
详解虚函数的实现过程之多重继承(3)
详解虚函数的实现过程之虚基类(4)
详解虚函数的实现过程之菱形继承(5)

详解虚函数的实现过程之菱形继承(5)相关推荐

  1. 详解虚函数的实现过程之菱形继承修罗场(6)

    在这里想跟大家一起来探索一下菱形继承的类对象如何来执行构造函数,以及析构函数 这展示了子类CSofaBed的构造过程,它的特别之处是在调用时要传入一个参数,这个参数是一个标志信息.构造函数中要先构造父 ...

  2. 详解虚函数的实现过程之单继承(2)

    从汇编分析一下下面的多态模拟结构 利用 父类指针指向子类的特性,可以间接调用各子类中的虚函数. 虽然指针类型为父类,但由于虚表的排列顺序是按虚函数在类继承层次中首次声明的顺序依次排列的,因此,只要继承 ...

  3. 详解虚函数的实现过程之虚基类(4)

    博客虚函数实现过程3 时提到过虚基类,这里呢,我们来详细讲述一下: 当我们在虚函数的声明结尾处添加"=0",这种虚函数就被称为纯虚函数. 它好似一个没有实现只有声明的函数,它的存在 ...

  4. 详解虚函数的实现过程之多重继承(3)

    下面来一起探索一下多重继承时,有虚函数会怎么继承呢? 这里大家猜一下,SofaBed会占多少个字节呢? 首先我们是不是得猜一下它有几个虚表指针? 4* 4(4个int数据)+2*4(两个虚表指针)=2 ...

  5. 详解虚函数的实现过程之初探虚表(1)

    空对象它有一字节的大小,在没有任何成员变量但是却有虚函数的对象里,它的大小是四个字节,这是为什么呢? 因为含有虚函数的对象里,对象的起始地址往后四个字节其实是 一个指针,它指向了一个数组,这个数组的元 ...

  6. python中可变参数*args传入函数时的存储方式为_python 中文读法详解Python函数可变参数定义及其参数传递方式...

    Python函数可变参数定义及其参数传递方式详解 python中 函数不定参数的定义形式如下 1. func(*args) 传入的参数为以元组形式存在args中,如: def func(*args): ...

  7. 一分钟详解initUndistortRectifyMap函数bug修复方法

    本文首发于微信公众号「3D视觉工坊」--一分钟详解initUndistortRectifyMap函数bug修复方法 在上一篇文章OpenCV中initUndistortRectifyMap函数存在bu ...

  8. python命名空间和闭包_Python函数基础实例详解【函数嵌套,命名空间,函数对象,闭包函数等】...

    本文实例讲述了Python函数基础用法.分享给大家供大家参考,具体如下: 一.什么是命名关键字参数? 格式: 在*后面参数都是命名关键字参数. 特点: 1.约束函数的调用者必须按照Kye=value的 ...

  9. 详解Scala函数也是对象的特性

    详解Scala函数也是对象的特性

最新文章

  1. iphone屏蔽系统更新_一招屏蔽系统更新!再见 iOS 13...
  2. 回顾2018——区块链行业十大关键词
  3. mac版小达人点读包怎么安装_小达人点读笔扩容实战:16G变128G
  4. 【CodeForces - 294B】Shaass and Bookshelf(枚举,贪心,思维,组内贪心组间dp)
  5. VerbalExpressions
  6. 认识一下Android 事件分发机制
  7. 2020牛客多校训练1 I 1or2(拆点拆边带花树一般图最大匹配)
  8. 最好看的css样式文字,二十款漂亮的CSS字体样式
  9. MongoDB Could not find host matching read preference { mode: “primary” } for set shard1
  10. android js回调函数,JavaScript回调函数的几种用法
  11. Flutter Dio 报错is not a subtype of type ‘DioError‘
  12. memory prefix hypo,hecto,hyper out1
  13. MATLAB凸优化工具箱CVX用户手册-Chapter5
  14. mbp使用brew安装unrar
  15. python中jieba分词,并输出词云(基础版)
  16. WeBRTC IOS视频采集流程
  17. 数据透视表的切片器实现数据动态交互
  18. 比chatgpt稍逊的ai问答网站phind,专用于编写代码
  19. 【程序设计基础 学习笔记】单向链表(TBC)
  20. 克服浮躁_如果您从事技术工作,那就克服自己

热门文章

  1. 小米机器人虚拟墙设置_扫地机器人虚拟墙应该怎么放置使用
  2. ML之FE:数据随机抽样之利用pandas的sample函数对超大样本的数据集进行随机采样,并另存为csv文件
  3. NVIDIA之AI Course:Getting Started with AI on Jetson Nano—Class notes(四)
  4. TF:利用TF读取数据操作,将CIFAR-10 数据集中的训练图片读取出来,并保存为.jpg格式
  5. CV:Win10下深度学习框架安装之Tensorflow/tensorflow_gpu+Cuda+Cudnn(最清楚/最快捷)之详细攻略(图文教程)
  6. Windows下编译jcef
  7. tomcat的访问日志
  8. Leetcode 436.寻找右区间
  9. ToStringBuilder学习(三):readResolve()方法与序列化
  10. BSEG和BSIS、BSAS、BSID、BSAD、BSIK、BSAK六个表的关系(转)