我看vc6中虚继承的实现

C++虚继承对象模型 1.为什么需要虚继承如下图所示如果访问Der::Fun or Der::m_nValue就会带来二义性,无法确定是调用Base1的还是Base2的,所以为了解决多重继承情况下成员访问的二义性,引入了虚继承机制。一般继承                                                                           虚继承2.虚继承实现在虚继承下,Der通过共享虚基类SuperBase来避免二义性,在Base1,Base2中分别保存虚基类指针,Der继承Ba 阅读详情
我看vc6中虚继承的实现

这两天试了一下,来说两句

因手头上只有vc6编译器,故只看了vc6的方式

我的测试程序如下
#include "stdafx.h"
class mostbase1
{
public:
 mostbase1():i(1){};
 int i;
};
class mostbase2
{
public:
 mostbase2():j(2){};
 int j;
};

class base1:public virtual mostbase1,public virtual mostbase2
{
};
class base2:public virtual mostbase1,public virtual mostbase2
{
};
class derived:public base1,public base2
{
};
void f(derived* pderived)
{
 mostbase1* pbase1 = pderived;
 mostbase2* pbase2 = pderived;
 int k = pderived->i;
 k = pderived->j;
 k = pbase1->i;
 k = pbase2->j;
}
int main(int argc, char* argv[])
{
 derived d;
 f(&d);
 printf("Hello World! ");
 return 0;
}
经过我的测试及查看汇编代码,得知vc的虚基类转换确如Inside the c++ objects model中所说是用一个virtual base class table来实现的
base1和base2中各有一个__vbct__ptr(大小是4个字节)用来指向一个virtual base class table,该表格存储着base类中虚基类在base类中的偏移,其后就是数据,当derived继承自base1和base2,首先是存放base1和base2的__vbct_ptr,再就是数据,将base1和base2相同基类的数据放到一起
base1类的内存布局如下(base2与base1相同):
pvoid* __vbct_base1  ----先是虚基类表的地址,此时__vbct_base1数据如下
      ----00 00 00 00 04 00 00 00 08 00 00 00
      ----mostbase1在base1中的偏移为[__vbct_base1+4]的值
int i;     ----mostbase1类中的i
int j;     ----mostbase2类中的j

derived类的内存布局如下:
pvoid* __vbct_base1; ----base1类的虚基类表的地址,其中的值有变化,数据如下
                                ----00 00 00 00 08 00 00 00 0C 00 00 00
pvoid* __vbct_base2; ----base2类的虚基类表的地址,数据如下
                                ----00 00 00 00 04 00 00 00 08 00 00 00
int i;
int j;

 


下面是f(derived* pderived)函数的汇编代码,对其它进行分析

29:   void f(derived* pderived)
30:   {
0040C230   push        ebp
0040C231   mov         ebp,esp
0040C233   sub         esp,60h
0040C236   push        ebx
0040C237   push        esi
0040C238   push        edi
0040C239   lea         edi,[ebp-60h]
0040C23C   mov         ecx,18h
0040C241   mov         eax,0CCCCCCCCh
0040C246   rep stos    dword ptr [edi]
31:       mostbase1* pbase1 = pderived;
0040C248   cmp         dword ptr [ebp+8],0          [1]
0040C24C   jne         f+27h (0040c257)
0040C24E   mov         dword ptr [ebp-18h],0        [2]
0040C255   jmp         f+35h (0040c265)
0040C257   mov         eax,dword ptr [ebp+8]
0040C25A   mov         ecx,dword ptr [eax]          [3]
0040C25C   mov         edx,dword ptr [ebp+8]
0040C25F   add         edx,dword ptr [ecx+4]        [4]
0040C262   mov         dword ptr [ebp-18h],edx
0040C265   mov         eax,dword ptr [ebp-18h]
0040C268   mov         dword ptr [ebp-4],eax        [5]
32:       mostbase2* pbase2 = pderived;
0040C26B   cmp         dword ptr [ebp+8],0
0040C26F   jne         f+4Ah (0040c27a)
0040C271   mov         dword ptr [ebp-1Ch],0        [6]
0040C278   jmp         f+58h (0040c288)
0040C27A   mov         ecx,dword ptr [ebp+8]
0040C27D   mov         edx,dword ptr [ecx]          [7]
0040C27F   mov         eax,dword ptr [ebp+8]  
0040C282   add         eax,dword ptr [edx+8]        [8]
0040C285   mov         dword ptr [ebp-1Ch],eax
0040C288   mov         ecx,dword ptr [ebp-1Ch]
0040C28B   mov         dword ptr [ebp-8],ecx
33:       base1* p1 = pderived;
0040C28E   mov         edx,dword ptr [ebp+8]
0040C291   mov         dword ptr [ebp-0Ch],edx      [9]
34:       p1->i = 1;
0040C294   mov         eax,dword ptr [ebp-0Ch]
0040C297   mov         ecx,dword ptr [eax]
0040C299   mov         edx,dword ptr [ecx+4]        [10]
0040C29C   mov         eax,dword ptr [ebp-0Ch]
0040C29F   mov         dword ptr [eax+edx],1
35:       base2* p2 = pderived;
0040C2A6   cmp         dword ptr [ebp+8],0
0040C2AA   je          f+87h (0040c2b7)
0040C2AC   mov         ecx,dword ptr [ebp+8]
0040C2AF   add         ecx,4                                 [11]
0040C2B2   mov         dword ptr [ebp-20h],ecx
0040C2B5   jmp         f+8Eh (0040c2be)
0040C2B7   mov         dword ptr [ebp-20h],0
0040C2BE   mov         edx,dword ptr [ebp-20h]
0040C2C1   mov         dword ptr [ebp-10h],edx      [12]
36:       p2->j = 1;
0040C2C4   mov         eax,dword ptr [ebp-10h]
0040C2C7   mov         ecx,dword ptr [eax]
0040C2C9   mov         edx,dword ptr [ecx+8]        [13]
0040C2CC   mov         eax,dword ptr [ebp-10h]
0040C2CF   mov         dword ptr [eax+edx],1
37:       int k = pderived->i;
0040C2D6   mov         ecx,dword ptr [ebp+8]
0040C2D9   mov         edx,dword ptr [ecx]
0040C2DB   mov         eax,dword ptr [edx+4]        [14]
0040C2DE   mov         ecx,dword ptr [ebp+8]
0040C2E1   mov         edx,dword ptr [ecx+eax]      [15]
0040C2E4   mov         dword ptr [ebp-14h],edx
38:       k = pderived->j;
0040C2E7   mov         eax,dword ptr [ebp+8]
0040C2EA   mov         ecx,dword ptr [eax]
0040C2EC   mov         edx,dword ptr [ecx+8]        [16]
0040C2EF   mov         eax,dword ptr [ebp+8]
0040C2F2   mov         ecx,dword ptr [eax+edx]
0040C2F5   mov         dword ptr [ebp-14h],ecx
39:
40:   }
0040C2F8   pop         edi
0040C2F9   pop         esi
0040C2FA   pop         ebx
0040C2FB   mov         esp,ebp
0040C2FD   pop         ebp
0040C2FE   ret


[1]dword ptr [ebp+8h]就是pderived,先看看是不是为NULL.
[2]dword ptr [ebp-18h]是一个中间变量,当pderived为NULL时,将其也赋为NULL
[3]取出__vbct_base1,其位置在derived类的开始处
[4]取出mostbast1类在derived中的偏移,此值在_vbct_base1+4的位置,占用4个字节,其值为8, 因为derived前有两个__vbct_prt,都为4字节,故mostbast1在derived的偏移为8.
[5]将pbase1赋值,dword ptr [ebp-4]存放pbase1;
[6]同(2),只是中间变量的地址不同
[7]同(3),取出__vbct_base1
[8]同(4), 取出mostbast2类在derived中的偏移,此时为12
[9]取出derived类中的base1的地址,也就是derived中__vbct_base1的地址,可能你有疑问,看下面
[10]用p1存取数据时,还是通过__vbct_base1来做的,通过__vbct_base1得到mostbase1在derived中 的偏移,最后得到的地址是pderived+8
[11]现在取出__vbct_base2的地址,看到了add ecx,4么
[12]将p2赋值
[13]通过__vbct_base2来取得mostbase2的地址,再来存取j
[14]通过__vbct_base1来取得mostbase1的地址
[15]偏移在eax中,取出i来
[16]通过__vbct_base1来取得mostbase2的地址

以下是我构想的c伪码,可能不太正确,因为汇编代码已经优化过
void f(derived* pderived)
{
 ----mostbase1* pbase1 = pderived;
 mostbase1 *pbase1,*temp1;
 if (pderived == 0)
 {
  temp1 = 0;
 }
 else
 {
  temp1 = (mostbase1*)(pderived+(pderived->__vbct_base1[1]));
 }
 pbase1 = temp1;

 ----mostbase2* pbase2 = pderived;
 mostbase2 *pbase2,*temp2;
 if (pderived == 0)
 {
  temp2 = 0;
 }
 else
 {
  temp2 = (mostbase2*)(pderived+(pderived->__vbct_base1[2]));
 }
 pbase2 = temp2;
 ----base1* p1 = pderived;
 base1* p1 = &pderived->__vbct_base1;
 ----p1->i = 1;
 (mostbase1*)(p1+p1->__vbct_base1[1])->i = 1;
 ----base2* p2 = pderived;
 base2* p2 = &pderived->__vbct_base2;
 ----p2->j = 1;
 (mostbase2*)(p2+p2->__vbct_base2[2])->j = 1;
 ----int k = pderived->i;
 int k = (mostbase1*)(pderived+pderived->__vbct_base1[1])->i;
 ----k = pderived->j;
 k = (mostbase2*)(pderived+pderived->__vbct_base1[2])->j;
}

C++ 虚继承的对象模型 我们知道,虚继承的基类在类的层次结构中只可能出现一个实例。虚基类在类的层次结构中的位置是不能固定的,因为继承了虚基类的类可能会再次被其他类多继承。   比如class A: virtual T{} 这时T的位置如果相对于A是固定值的话,假设偏移是X,当再有个类 class B:virtual T{} ;这时假设在B里面T的偏移是固定的Y,而当再有一个类,class C: B, A {} 的时候 阅读详情

相关推荐

c++虚继承对象的内存布局

c++虚继承对象的内存布局               --VC7.1特别版网上关于c++对象布局的文章挺多,而且《深度探索c++对象模型》(Inside The C++ Object Model 侯捷 译)一书中也很详细地介绍。如果你一点都不了解C++对象的布局,我推荐你看看《深度探索c++对象模型》的第三章,如果你意犹未尽下面的两个系列都很不错:一是陈皓的《C++ 对象的内存布

BlueDog专栏 1万+

VC++之 继承

一.继承的引出 自然界中很多客观事物具有很多共性,比如人与猿之间、火车与汽车之间、大炮与机枪之间,明显地有很多共性,但是它们之间又有很多不同。C++解决 “类似但有不同”问题的方法是——允许类从一个或多个其他类(在这里称为基类)继承其特性和行为,参看下面的例子: //--------------------------------------------------- class Pri...

weixin_30399797的博客 247

笔记——Oracle19c

Oracle阅读笔记

weixin_63819458的博客 1348

(转载)虚继承之单继承的内存布局

原博客在http://blog.youkuaiyun.com/rkfang/article/details/131567 C++2.0以后全面支持虚函数与虚继承,这两个特性的引入为C++增强了不少功能,也引入了不少烦恼。虚函数与虚继承有哪些特性,今天就不记录了,如果能搞了解一下编译器是如何实现虚函数和虚继承,它们在类的内存空间中又是如何布局的,却可以对C++的了解深入不少。这段时间花了一些时间了解这些玩

梦北 735

手把手教你用UNI-MOL进行分子性质预测:从3D构象到实战结果

本文提供了使用UNI-MOL进行分子性质预测的完整实战指南。通过详细的环境搭建、3D构象生成、模型加载与微调步骤,手把手教你构建端到端的预测流水线。文章重点解析了如何利用UNI-MOL的3D分子表示学习能力,超越传统2D方法,实现对溶解度、活性等性质的更精准预测,并探讨了结果解读与模型分析方法。

weixin_29164091的博客 116

ST电机库实战:从状态机到稳健启动流程的深度解析

本文深度解析了ST电机库中状态机的核心作用与稳健启动流程。状态机作为电机控制的“交通指挥官”,通过IDLE、CHARGE_BOOT_CAP、ALIGNMENT等一系列状态的严格跳转,确保了永磁同步电机(PMSM)和直流无刷电机(BLDC)的安全启动与可靠运行,是避免硬件损坏和实现平稳控制的关键。

weixin_29161785的博客 224

虚函数的继承

C++2.0以后全面支持虚函数与虚继承,这两个特性的引入为C++增强了不少功能,也引入了不少烦恼。虚函数与虚继承有哪些特性,今天就不记录了,如果能搞了解一下编译器是如何实现虚函数和虚继承,它们在类的内存空间中又是如何布局的,却可以对C++的了解深入不少。这段时间花了一些时间了解这些玩意,搞得偶都,不过总算有些收获,嘿嘿。      先看一段代码   class A   {    ...

weixin_30340353的博客 64

NU1680无线充电接收器在TWS耳机中的应用实战:I2C调压与QI协议适配

本文详细解析了NU1680无线充电接收器在TWS耳机充电仓设计中的应用实战。重点阐述了其无固件设计、I2C接口动态调压功能如何解决不同QI协议发射器的兼容性难题,并分享了硬件设计、PCB布局、与发射端联调及安全测试等关键环节的实践经验,助力开发者快速实现稳定高效的无线充电方案。

weixin_28432777的博客 232

VC如何实现的虚继承

大家知道C++中可以使用虚继承,而为什么虚继承基类的构造函数只会被构造一次呢?原来VC在生成虚继承基类子类对应的构造函数和调用代码时,给构造函数多加了一个参数,这个参数是一个布尔知。如果为True(1),则我们实际在构造实际的对象,这时构造函数会调用其所有虚继承基类的构造函数,无论这虚继承基类是这个类的多少辈祖先。而且只有这个对象才知道虚继承基类在自己类中的内存偏移,别人也无法进行虚继承基类的构造

879

逆向某团mtgsig参数时,我踩过的3个坑:从H5guard混淆到Python校验

本文详细解析了逆向某团mtgsig参数时遇到的三大挑战:H5guard混淆破解、环境补全检测与Python结果校验。通过实战案例,揭示了JavaScript加密算法的逆向技巧,包括控制流混淆拆解、隐蔽环境检测点规避以及跨语言校验的解决方案,为开发者提供了一套完整的逆向工程避坑指南。

weixin_27722377的博客 1061

uniapp - [微信小程序] 实现点击预览各种文件 pdf文档、视频mp4、mp3音乐、图片图像、word/excel/ppt 等,uniapp小程序文件预览功能(详细示例代码,一键复制开箱即用)

uniapp,uniapp微信小程序,支付宝小程序平台端,uniapp实现文件在线预览,uniapp微信小程序怎么实现预览视频mp4,mp3音乐,图片,office文档,小程序平台如何在线预览word/excel/ppt文档,uniapp实现小程序端的文件查看功能,uniapp小程序端实现pdf文件预览,uniapp纯前端预览PDF、DOC、DOCX、图片、视频,uni-app文档、图片预览查看,uniapp文档预览功能,uniapp小程序端文件预览,uniapp小程序平台纯前端解析word,pdf,xls

✅ 精选推荐文章 1万+

虚继承及继承的内存布局

1.为什么需要虚继承 如下图所示如果访问Der::Fun or Der::m_nValue就会带来二义性,无法确定是调用Base1的还是Base2的,所以为了解决多重继承情况下成员访问的二义性,引入了虚继承机制。 一般继承: 虚继承: 2.虚继承实现 在虚继承下,Der通过共享虚基类SuperBase来避免二义性,在Base1,Base2中分别保存虚基类指针,Der继承Base1,Base...

sunweiliang的博客 381

PyTorch深度学习实战(39)——少样本学习(Few-shot Learning)

小样本学习 (Few-shot Learning) 旨在解决在训练集中只有很少样本的情况下进行分类和推理的问题。在小样本学习中,我们希望通过利用已有的少量样本和先验知识来进行泛化,以便在面对新的、未见过的类别时能够做出准确的预测。这就要求模型能够从有限的训练样本中提取出有用的信息,并能够将这些信息应用到新类别的样本中去。在本节中,将介绍孪生、原型和关系网络的原理,并使用 PyTorch 实现孪生网络。

盼小辉丶的博客 1万+

C++ 虚继承与普通继承的内存模型对比

实验小结:对虚继承中编译器不同内存分配也不同。 //1.vc6.0中虚继承除了自己有虚函数时有虚指针(没有虚函数时就不加自身的这个虚指针)+另外还有添加一个“公用继承虚指针”+再加上基的空间 //2.gcc或codeblock中就没有添加“公用继承虚指针”,会比vc6.0中少4位,但如有虚函数时就有虚指针,最后还要加上基的空间 //相比1.少了4 //3.对于不是虚继承而是一把的继承就会没有

lu1012123053的专栏 1460

手把手教你学simulink实例:基于Simulink的风力发电系统建模与仿真

风力发电作为一种清洁、可再生的能源形式,近年来得到了快速发展。风力发电系统的性能优化和控制策略设计对于提高发电效率、降低运行成本具有重要意义。本项目旨在使用MATLAB/Simulink平台,对风力发电系统进行建模与仿真,研究其动态特性,并验证控制策略的有效性。通过建立风力发电机、传动系统、发电机及电力电子变换器等子系统的模型,实现对风力发电系统的全面分析。

MHD0815的博客 558

android 蓝牙通讯demo

android 下蓝牙通讯demo,实现了发现蓝牙,使能蓝牙,通过蓝牙发送消息。

VC、GCC及Clang中C++虚继承和虚函数的内存布局

测试代码如下: 1#include <stdio.h> 2 3class A 4{ 5public: 6 int a; 7 virtual ~A(void){} 8}; 9class B : virtual public A 10{ 11}; 12class C : virtual public A 13{ 14 virtual void FuncC(void) ...

Poo_Chai的博客 1788

pscad IEEE标准系统搭建说明

pscad IEEE标准系统搭建说明,包含典型的IEEE 9节点、14节点、30节点、39节点和118节点系统。内含标准测试系统的原始数据和潮流结果。

GCC VC6.0 编译器下 C++虚继承内存大小

针对于gcc vc 编译器 对虚继承内存大小的分析

XD_122 1192

Statistics and Machine Learning Toolbox

Statistics and Machine Learning Toolbox(带书签),MATLAB统计学习工具

假人有限元模型

假人模型,车辆碰撞假人有限元模型,适合做乘员安全的研究者利用

C++中虚继承的内存布局

看了 《Inside c++ object model》 想到一个题目: #include <iostream>using namespace std;class A{virtual void f(){};};class B : public virtual A{ virtual void f(){};};class C: public virtual A{v...

weixin_30556161的博客 164

虚继承内存布局(2019.10.22)

转载自:http://blog.youkuaiyun.com/xsh_123321/article/details/5956289 1.为什么需要虚继承 如下图所示如果访问Der::Fun or Der::m_nValue就会带来二义性,无法确定是调用Base1的还是Base2的,所以为了解决多重继承情况下成员访问的二义性,引入了虚继承机制。 一般继承 ...

smilesundream的博客 503

浅谈VC2003对C++虚继承/共享继承实现

在虚继承/共享继承中,类对象,会额外增加一个表头指针——虚基类表。 这里设定的虚继承模型为: class A #if !defined(_A_H) #define _A_H /** * \brief A类。 */ class A { public: virtual void TestA() { printf( "TestA\r\n" ); }

ItghostFan的专栏 336

虚继承和虚函数

update:6/6,面向对象程序设计 虚函数 在一个基类中声明一个函数为virtual类型,即virtual void Run();那么这个函数就是虚函数, 作用:实现多态,父类型别的指针指向其子类的实例,然后通过父类的指针调用实际子类的成员函数。 我这里是 class vehicle{ public: int MaxSpeed; int Weight; vi...

TYtrack的博客 1182

C++ 虚继承

源自:http://blog.youkuaiyun.com/xsh_123321/article/details/5956289 1.为什么需要虚继承 如下图所示如果访问Der::Fun or Der::m_nValue就会带来二义性,无法确定是调用Base1的还是Base2的,所以为了解决多重继承情况下成员访问的二义性,引入了虚继承机制。 一般继承

星星之火 1971

C++虚继承

本文是有文章末尾的问题引起: 原文链接为:http://hi.baidu.com/absolute8511/blog/item/2846613d0fb29ae73d6d978f.html   这篇文章写得很好,一看就让人明白虚继承到底是怎么回事。而我之所以说从它引起是因为我是在使用Inside C++中的讲解virtual int size()函数的时候去测试类大小,我忘记了父类的

走出憧憬的专栏 746

C++虚继承内存对象模型探讨

From: http://hi.baidu.com/absolute8511/blog/item/2846613d0fb29ae73d6d978f.html C++虚继承内存对象模型探讨最近看了下Inside C++里面讲的对虚继承层次的对象的内存布局,发现在不同编译器实现有所区别。因此,自己动手探索了一下。结果如下:首先,说说GCC的编译器.它实现比较简单,不管是否虚继承,G

chaosllgao的专栏 596
上一篇: STL iterator 基本原则
下一篇: 标准C++模板库 下载
manplus
博客等级 码龄22年 6粉丝 160原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值