c++对象内存布局(转)

10xGenomics官方可视化工具——Loupe Browser Loupe Browser是⼀款10xGenomics开发的交互式桌⾯应⽤程序,⽤于探索10x单细胞数据,可以用来找出感兴趣的细胞、找出显著差异表达的基因、鉴定细胞类型、探索细胞亚类和数据共享。 阅读详情
c++对象内存布局

   写这个文章完全是因为想要搞清楚 vc 怎么布局每个 c++ 对象,以及怎样完成指针的转换的过程.
  先问一个问题,两个不同类型的指针相互转换以后,他们在数值上是一样的吗?比如:

    int nValue = 10;
    int *pInt = &nValue;
    void *pVoid = pInt;
    char *pChar = (char*)pInt;


  这些指针的值(不是说指针指向的内存的内容)是一样的吗? 如果你的回答是 yes,那如果是一个类的继承体系呢?在继承类向基类转换的过程中,指针的数值还是不变化的么?如果你的回答是"不一定会变化,要看类的体系是怎么设计的"的话,那恭喜你,不用看下去了.如果你还不确定究竟变还是不变,究竟哪些变,哪些不变,究竟为什么要变为什么不变的话,接着看下来.

  c++ 标准不规定 c++ 实现的时候的对象的具体的内存布局,除了在某些方面有小的限制以外,c++ 对象在内存里面的布局完全是由编译器自行决定,这里我也只是讨论 vc++ .net 2003 build 7.1.3091 的实现方式,我并没有在 vc5 vc6 vc.net 2002 以及其他的 2003 build 上面做过测试,结论也许不适合那些编译平台.这些属于编译器具体实现,ms 保留有在不通知你我的情况下作出更改的权利.废话这么多,马上开始.

  对于 c 的内建指针的转换,结果是不用多讨论的,我们只是讨论 c++ 的对象.从最简单的开始.

    class CBase
    {
    public:
      int m_nBaseValue;
    };


  这样的一个类在内存里放置是非常简单的,他占有4个 bytes 的空间,不用多说,我们从他派生一个类出来.

    class CDerive1 : public CBase
    {
    public:
      int m_nDerive1Value;
    };


  CDerive1 的对象在内存里面是怎么放的呢? 也很简单,占有8个 bytes 的空间,前4个 bytes 属于 CBase 类,后四个 bytes 属于自己.一个CDerive1 的指针转换成一个 CBase 的指针,结果是一样的.下面我们加上多重继承看看.

    class CFinal : public CDerive,public CBase // 这里的 CDerive 是一个和 CBase 差不多的基类
    {
    public:
      int m_nFinalValue;
    };


  CFinal 的对象在内存里面的布局稍微复杂一点,但是也很容易想象,他占有 12 个 bytes 的空间,前4个属于 CDerive,中间4个属于 CBase,后面4个才是自己的.那一个 CFinal 的指针转换成一个 CDerive 指针,数值会变么? 转换成一个 CBase 指针呢?又会变化么?答案是,前一个不变,后一个要变化,道理非常的明显,CFinal 对象的开头刚好是一个 CDerive 对象,而 CBase 对象却在 CFinal 对象的中间,自然是要变化的了,具体怎么变化呢? 加 4 就 ok(自然要检查是否是空指针).

    CBase *pBase = pFinal ? (CBase*)((char*)pFinal + sizeof(CDerive)) : 0;// 当你写下 pBase = pFinal 的时候,其实是这样的

  这种不带 virtual 的继承就这么简单,只是加上一个 offset 而已.下面我们看看如果加上 virtual function 的时候是什么样子的呢?
还是从简单类开始.

    class CBase
    {
    public:
      virtual void VirtualBaseFunction(){}
      int m_nBaseValue;
    };


  这里刻意没有使用 virtual destructor,因为这个函数稍微有些不同.还是同样的问题,CBase 类在内存上占多大的空间?还是 4 bytes 么? 答案是 no, 在我的编译器上面是 8 bytes,多出来的 4 bytes 是 __vfptr(watch 窗口看见的名字),他是一个指针,指向了类的 vtable,那什么是 vtable 呢,他是用来干什么的呢? vtable 是用来支援 virtual function 机制的,他其实是一个函数指针数组(并不等同于c/c++语言里面的指针数组,因为他们的类型并不一定是一样的.)他的每一个元素都指向了一个你定义的 virtual function,这样通过一个中间层来到达动态连编的效果,这些指针是在程序运行的时候准备妥当的,而不是在编译的时候准备妥当的,这个就是动态联编的目的,具体是由谁来设置这些指针的呢?constructor/destructor/copy constructor/assignment operator他们完成的,不用奇怪,编译器会在你写的这些函数里面安插些必要的代码用来设置 vtable 的值,如果你没有写这些函数,编译器会在适当的时候帮你生成这些函数.明白一点, vtable 是用来支持 virtual function 机制的,而需要 virtual 机制的类基本上都会由一个 __vfptr 指向他自己的 vtable.在调用 virtual function的时候,编译器这样完成:

   pBase->VirtualBaseFunction(); => pBase->__vfptr[0](); // 0 是你的virtual function 在 vtable 中的 slot number,编译器决定

  现在应该很想象 CBase 的大小了吧,那这个 __vfptr 是放到什么位置的呢? 在 m_nBaseValue 之前还是之后呢? 在我的编译器上看来,是在之前,为什么要放到之前,是因为在通过 指向类成员函数的指针调用 virtual function 的时候能少些代码(指汇编代码),这个原因这里就不深入讨论了,有兴趣的同学可以看看 inside the c++ object model 一书.
  接下来,我们加上继承来看看.

    class CDerive1 : public CBase
    {
    public:
      virtual void VirtualDerive1Function();
    };


  这个时候你也许要说,内存布局跟没有 virtual 是一样的,只不过每个类多了一个 __vfptr 而已,呃...这个是不对的,在我的编译器上面 两个类共享同一个 __vfptr, vtable 里面放有两个指针,一个是两个类共享的,一个只属于 CDerive1 类,调用的时候如何呢?

   pDerive1->VirtualDerive1Function() => pDerive1->__vfptr[1]();
   pDerive1->VirtualBaseFunction() => pDerive1->__vfptr[0]();


  至于指针的相互转换,数值还是没有变化的(也正是追求这种效果,所以把 __vfptr 放到类的开头,因为调整 this 指针也是要占有运行时的时间的).

  现在加上多重继承瞧瞧,代码我不写上来了,就跟上面的 CFinal, CDerive, CBase 体系一样,只是每个类多一个VirtualxxxFunction出来,这个时候的指针调整还是没有什么变化,所以我们只是看看 vtable 的情况,你会说 CDerive 和 CFinal 共享一个 __vfptr,而 CBase 有一个自己的 __vfptr,而 CFinal 的 __vfptr 有 2 个slot,这个结论是正确的. 同时你也会说 通过 CFinal 类调用 CBase 的函数是要进行指针调整的,yes you'r right,不仅仅是 this 指针调整(呃,this 指针会成为 function 的一个参数),还要调整 vtable 的值:

   pFinal->VirtualBaseFunction() => (CBase*)((char*)pFinal + sizeof(CDerive))->__vfptr[0]();

   转换成 asm 的代码大约是这样的:

   mov eax,[pFinal] ; pFinal is a local object,pFinal will be epb - xx
   add eax,8 ; 8 = sizeof(CDerive)
   mov ecx,eax ; ecx is this pointer
   mov edx,[eax] ; edx = vtable address
   call [edx] ; call vtable[0]


  写到这里也就明白this指针是怎么调整的.带 virtual function 的继承也不复杂,this指针调整也是很简单的,下面看最复杂的部分 virtual inheritance.

  我的编译器支持虚拟继承的方式和虚函数的方式差不多,都是通过一个 table 完成,只是这个就看不到 vc 赋予的名字了,我们叫他 vbtable 吧,编译器同样在类里面加入一个指向 vbtable 的指针,我们叫他 __vbptr 吧,这个指针指向了 vbtable ,而 vbtable 里面的每一项对应了一个基类,vbtable 记录了每个基类的某一个偏移量,通过这个偏移量就能计算出具体类的指针的位置.看个简单的例子:

   class CBase
   {
   public:
     virtual ~CBase(){}
   };

   class CMid1 : public virtual CBase
   {
   public:
     virtual ~CMid1(){}
     int m_nMid1;
   };

   class CMid2 : public virtual CBase
   {
   public:
     virtual ~CMid2(){}
     int m_nMid2;
   };

   class CFinal : public CMid1,public CMid2
   {
   public:
     virtual ~CFinal(){}
     int m_nFinal;
   };

   CFinal final;
   CFinal *pFinal = &final;    // pFinal = 0x0012feb4;
   CBase *pBase = pFinal; // pBase = 0x0012fec8 = pFinal + 0x14;
   CMid1 *pMid1 = pFinal; // pMid1 = 0x0012feb4 = pFinal;
   CMid2 *pMid2 = pFinal; // pMid2 = 0x004210b4 = pFinal;


  结果让你吃惊吗? 最奇怪的地方居然是 CMid2 和 CMid1 的地址居然是一样的,这个是因为 vc 把 vbtable 放到了 CFinal 类的开头的原因,而CMid1 和 CMid2 也同样要使用这个 vbtable, 所以 这个三个的地址也就必须相同了.那 CBase 的地址是怎么出来的呢? 呃...刚刚我们说了 vbtable 放到了CFinal 的开头(vc 一定会放在开头吗?答案是不一定,这个稍后解释).在我的机器上面 final 对应内存的第一个 dword 是 0x00426030,查看这个地址,第一个dword 是 0 ,第二个就是 0x14,刚好和 pBase 的偏移相同,这个只是巧合,也许你换个类的继承体系就完全不同了,但是我只是想说明一点,基类的偏移计算是和 vbtable 的值相关联的.下面我们就来看看 vc 是怎么计算这些偏移的.
  vc 在分析我们的代码的时候,生成了一份类的继承体系信息,其中有一个叫 thisDisplacement 的_PMD结构:

    struct _PMD // total undocumented
    {
      int mdisp; // i think the meaning is Multiinheritance DISPlacement
      int pdisp; // Pointer to vbtable DISPlacement
      int vdisp; // Vbtable DISPlacement
    };


  结构的名字和成员变量的名字确确实实是 vc 的名字(在 watch 窗口输入 (_PMD*)0 就能看到这个结构的详细信息),每个字段的含义却是我自己猜测出来的.mdisp 大概用来表示多重继承(包括单一继承)的时候的偏移量,pdisp 表示 vbtable 的偏移量,而 vdisp 表示类在 vbtable 里面的下标.那么有了这个结构怎样才能完成指针的转换呢?假如我们有一个派生类指针 pFinal,要转换成一个特定的基础类,我们首先要知道和这个基类对应的 _PMD 结构的信息(这个信息的获取,我暂时没有找到一个非常方便的方法,现在我使用的方法下面会有描述),有了这个信息以后,转换就方便了.首先找到 vbtabel 的地址 *(pFinal + pdisp),然后找到基类的偏移 *(*(pFinal + pdisp) + vdisp) 这个偏移值是相对vbtable的,所以还要加上 vbtable的偏移,最后加上 mdisp的偏移,如下:

  char *pFinal = xxx; // need a init value
  char *pBase; // we must calc
  pBase = pFinal + mdisp + *(int *)(*(int *)(pFinal + pdisp) + vdisp) + pdisp;


  注意: 当 pdisp < 0 的时候就表示这个类没有 vbtable 直接使用 pFinal + mdisp 就得到结果了.
  所以这个结构是一个通用的结构,专门用作类型转换,不管是有无虚继承都能使用这个结构进行类型转换.

  通过这个结构,我们也能看到 vc 是怎样布局这个 object 的.

  看到这里,也许你要大呼一口气,妈妈呀,一个类型转换要这么的麻烦吗?我直接写 pBase = pFinal 不就可以了吗? 恭喜你还没有被我忽悠得晕头转向,哈哈.其实你写下那行语句的时候,编译器在帮你做这个转换,大约生成下面的代码

    mov eax,[pFinal] ;final address
    mov ecx,[eax] ; vbtable address *(int *)(pFinal + pdisp)
    mov edx,eax ; save to edx
    add edx,[ecx + 4] ; ecx + 4 is (*(int *)(pFinal + pdisp) + vdisp)
    mov [pBase],edx ; edx = pFinal + mdisp + *(int *)(*(int *)(pFinal + pdisp) + vdisp) + pdisp;
    ; here mdisp = 0, pdisp = 0, vdisp = 4


  也许你要说了,我要这些东西来干什么?要转换的时候直接转换就好了,编译器会帮做,的确,大多数的时候确实是这样,但是,在某些时候却并不如此,现在你要实现一个功能,输入一个指针,输入一个 _PMD 结构,你要实现一个AdjustPointer 的函数来生成另一个指针.这个时候你也只能这样完成了,因为我没有给你两个指针的名字,就算给了你字符串形式的名字也没有用,呃....你也许会说,办法是有的,的确是有,模板就能实现这种功能,呵..这个我们暂时不讨论具体的实现细节.也许你要问了,究竟什么时候会去实现这种听都没有听过的功能,其实这个函数是真正存在的,只不过不是由你来实现的,而是 ms 的人实现的,你只用写一个 带有 c++ 异常的程序,使用 ida 反汇编,然后查找函数,就能找到这个函数了,他用来在异常处理时创建 catch 所需要的 object.至于这个详细的信息,请期待.我会最快速度写出关于 vc 是怎样实现 c++ 异常的文章来.

  最后了,说说那个 _PMD 结构的获取方式.看的时候不要吃惊,方法比较的麻烦,比如我想知道和 CFinal 类相关的 _PMD 信息,先新建工作,写下 throw pFinal 这样的语句,编译,在这个语句的地方设置断点,运行,转到反汇编,进入 __CxxThrowException@8 函数,这个时候不出意外你能看到一个叫 pThrowInfo 的东西(如果看不到,请打开"显示符号名"选项),在 watch 窗口里面输入pThrowInfo,展开他,看到一个pCatchableTypeArray,记录下他的 nCacthableTypes的值,然后在 watch 里面输入
pThrowInfo->pCatchableTypeArray->arrayOfCatchableTypes[0] 到 pThrowInfo->pCatchableTypeArray->arrayOfCatchableTypes[n], n 就是你刚刚记录的值减1,再展开他们,你就能看到一个 thisDisplacement 的数据,继续展开就是 mdisp 等等了,很是麻烦吧.哈..你已经猜到了,这个是和异常有关系的.

  后记: 这段时间,我一直在读些反汇编之后的代码,也颇有些心得,所以才有想法写一些文章,探讨 vc 编译器鲜为人知(太过狂妄了)的秘密,这个方面的文章也有人写过,那些文章也给我不少的启发,我不认为自己是第一个发现这些秘密的人,但是至少我自己知道的,我是第一个把这些东西写出来的人.文章里面作墨多的部分都是自己发现的.就这个文章里面的内容来说,inside the c++ object model 是有比较详细的描写,但是他并不是转换针对 vc 这个编译器的实现,而 _PMD 这个结构我也没有在什么地方见有人描述过,只是在 windows develop network 的2002年12月的杂志上看有人提到过这个结构,可惜他却没有了解(至少他在他发表文章的时候是如是说的)这个结构的用处(正是因为这个原因,我才有写这个文章以及后续文章的冲动).所以,这个文章也算是我自己的原创吧.这个文件虽然和游戏制造没有太大的关系,但是小 T 自视清高,不愿意自己的文章被一帮不懂的人评价来评价去的,所以也没有发到那些著名的 xxx 网站,只发 goldpoint.转载请注明出处(小 T 对自己的第一个原创文章比较珍惜,比较重视,谢谢).
GPIB通讯的代码怎么写 GPIB(General Purpose Interface Bus)是一种用于连接计算机和测试设备的接口标准。 在写 GPIB 通讯的代码时,首先需要在计算机上安装 GPIB 驱动程序。然后,使用相应的编程语言和 GPIB 库函数来操作 GPIB 设备。 下面是一个使用 Python 语言和 pyvisa 库来实现 GPIB 通讯的示例代码: import visa# 创建 Visa 资源管理器... 阅读详情

相关推荐

保姆级教程:用Unity为麒麟系统打包Linux应用(含路径权限全攻略)

本文提供了一份详细的Unity跨平台开发指南,重点介绍如何在麒麟系统上打包和部署Linux应用。从开发环境配置、路径权限处理到性能优化和常见问题解决,全面解析了Unity项目在国产操作系统上的适配流程,帮助开发者高效完成跨平台应用开发。

weixin_28692867的博客 504

【转】C++类(Class)总结,经典易懂

C++/MFC,转自:小熊之家,作者ID:先之

lxq389509191的博客 444

AI人工智能领域多模态大模型的数字孪生应用

本文旨在系统性地介绍多模态大模型在数字孪生领域的最新应用进展,探讨其技术原理、实现方法和应用价值。内容范围涵盖从基础概念到前沿技术,从理论分析到实践案例。文章首先介绍多模态大模型和数字孪生的基本概念,然后深入分析两者的结合点,接着通过具体案例展示应用实践,最后探讨未来发展趋势和挑战。多模态大模型:能够同时处理和融合多种数据模态(如文本、图像、视频、音频等)的大型人工智能模型数字孪生:物理实体或系统的虚拟副本,通过实时数据同步实现虚实交互跨模态融合:将不同数据模态的信息进行有效整合和关联的技术。

AI云原生与云计算技术学院 1325

c++对象,内存布局

c++对象内存布局Wednesday, 14. June 2006, 06:25:29   写这个文章完全是因为想要搞清楚 vc 怎么布局每个 c++ 对象,以及怎样完成指针的转换的过程.  先问一个问题,两个不同类型的指针相互转换以后,他们在数值上是一样的吗?比如:    int nValue = 10;    int *pInt = &nValue;    void *pVoid =

877

Photoshop免费获取指南:官方试用与开源替代方案详解

图像处理软件是数字内容创作的核心工具,其工作原理基于像素编辑、图层叠加与算法滤镜。这类软件的技术价值在于为设计师、摄影师和内容创作者提供了强大的视觉表达能力,广泛应用于平面设计、UI/UX、摄影后期及社交媒体内容制作等场景。在众多工具中,Adobe Photoshop以其全面的功能和行业标准地位备受关注。对于希望免费体验或使用的用户,存在合法且安全的途径。其中,Adobe官方提供的7天免费试用版允许用户在安全环境下体验完整功能,而开源替代方案如GIMP则提供了长期免费的强大图像编辑能力。理解这些合法获取方式

cigang4063的博客 523

1999年-2022年 上市公司-企业劳动生产率数据(原始数据、代码、最终结果、参考文献)

上市公司企业劳动生产率数据集为企业和市场参与者提供了一个深入分析企业生产效率和劳动效益的工具。通过这些数据,企业可以不断探索创新的发展模式和管理方式,努力提高生产效率,为提升市场竞争力和盈利能力做出贡献。数据名称:上市公司-企业劳动生产率数据数据年份:1999-2022年数据来源:国泰安数据库1999年-2022年 上市公司-企业劳动生产率数据(原始数据、代码、最终结果、参考文献)

2401_84585615的博客 881

C++对象内存布局(转载)

C++对象内存布局(转载) 转载地址:http://www.cppblog.com/stdyh/archive/2007/01/08/17442.html 写这个文章完全是因为想要搞清楚 vc 怎么布局每个 c++ 对象,以及怎样完成指针的转换的过程.   先问一个问题,两个不同类型的指针相互转换以后,他们在数值上是一样的吗?比如:     int nValue = 10;

blacet的学习点滴 420

R语言数据可视化:绘制世界地图的两种方案

本文介绍了两种使用R语言绘制世界地图的方案:包含边界边框和不包含边界边框。无论您选择哪种方案,使用ggplot2包和相关的地理数据包,我们可以轻松地绘制出漂亮的世界地图。R语言提供了丰富的包和函数,使我们能够轻松地绘制世界地图,并根据需求添加边界边框。在本文中,我将介绍两种绘制世界地图的方案:一种包含边界边框,一种不包含边界边框。在上述代码中,我们使用了与方案一相同的数据准备和地图绘制步骤,但省略了添加边界边框的代码。函数的调用,我们可以绘制不包含边界边框的世界地图。方案二:绘制不包含边界边框的世界地图。

CodeMaven的博客 2225

C++中的虚函数(表)实现机制以及用C语言对其进行的模拟实现

前言C++对象的内存布局 只有数据成员的对象没有虚函数的对象拥有仅一个虚函数的对象拥有多个虚函数的对象单继承且本身不存在虚函数的继承类的内存布局本身不存在虚函数(不严谨)但存在基类虚函数覆盖的单继承类的内存布局定义了基类没有的虚函数的单继承的类对象布局多继承且存在虚函数覆盖同时又存在自身定义的虚函数的类对象布局如果第1个直接基类没有虚函数(表)What if 两个基类都没有虚函数表如果有三个

大自然的小女孩 1039

华为OD机试真题:明日之星选举 (Java/Py/C/ C++/JS/GO)

华为OD机试(机考)双机位C卷 【明日之星选举】,提供Java、C++、Python、Go、JavaScript源码实现,并提供完整思路讲解,以及在线OJ模拟做题。华为OD机试 - 明日之星选举。

qq_45776114的博客 919

Centos 7 Linux 安装单机 Hadoop(HDFS):下载、安装、配置、测试

本文详细介绍了在 CentOS 7 系统上安装与配置单机 Hadoop(HDFS)的完整流程,涵盖 JDK 环境准备、Hadoop 安装包下载与部署、核心配置文件(core-site.xml、hdfs-site.xml 等)修改、SSH 免密登录设置、HDFS 格式化及服务启动,并通过命令行与 Web 界面验证 HDFS 和 YARN 功能,适合 Hadoop 初学者快速搭建本地测试环境。

寒水馨 · 轻量级技术文档 · hanshuixin.org 3235

(转)C++对象的内存布局

原文地址:http://blog.youkuaiyun.com/haoel/article/details/3081328 C++对象的内存布局 陈皓 http://blog.youkuaiyun.com/haoel 前言 07年12月,我写了一篇《C++虚函数表解析》的文章,引起了大家的兴趣。有很多朋友对我的文章留了言,有鼓励我的,有批评我的,还有很多问问题的。我在这里一并对大家的留...

84

DeepLabv3+改进68:全网首发-添加DBlock模块 |高效且鲁棒的多任务低光图像修复神经网络

本文提出了一种高效鲁棒的多任务低光图像修复神经网络DarkIR,针对夜间或昏暗条件下图像存在的噪点、光线不足和模糊问题。不同于现有方法分别处理去模糊和低光增强任务,该模型采用新的注意力机制增强CNN感受野,在降低计算成本的同时,在LOL-Blur、LOLv2和Real-LOLBlur数据集上取得最优结果,并能良好泛化到真实夜间图像。

AIcurator的博客 325

C++ 对象的内存布局(上)(转)

C++ 对象的内存布局(上) 陈皓http://blog.youkuaiyun.com/haoel  点击这里查看下篇>>>前言 07年12月,我写了一篇《C++虚函数表解析》的文章,引起了大家的兴趣。有很多朋友对我的文章留了言,有鼓励我的,有批评我的,还有很多问问题的。我在这里一并对大家的留言表示感谢。这也是我为什么再写一篇续言的原因。因为,在上一篇文章中,我用了的示例都是非常简

gxj1680的专栏 788

精雕软件(JDpaint) 5.5 绿色版

精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版

ssm框架搭建

这个是一个在idea上成功跑起来的ssm框架项目,保存在这里方便以后使用直接下载

[转]图说C++对象模型:对象内存布局详解

转自:http://mp.blog.youkuaiyun.com/postedit 阅读目录 0.前言 1.何为C++对象模型? 2.文章内容简介 3.理解虚函数表 3.1.多态与虚表 3.2.使用指针访问虚表 4.对象模型概述 4.1.简单对象模型 4.2.表格驱动模型 4.3.非继承下的C++对象模型 5.继承下的C++对象模型 5.1.单继承 5.2.多继承 6.虚继承 6.1.虚基类表解析 6.2.简单虚继承 6.3.虚拟菱形继承 7....

oykotxuyang的博客 199

win10 跳过U8环境检测的IE WebControls.rar

win10 安装u8的时候 提示IE WebControls 不通过,这个工具可以欺骗u8的检查。 跳过U8环境检测的IE WebControls。提示导入失败后,重新检测通过。

C++ 对象的内存布局(下)(转)

C++ 对象的内存布局(下) 陈皓http://blog.youkuaiyun.com/haoel  <<<点击这里查看上篇  重复继承 下面我们再来看看,发生重复继承的情况。所谓重复继承,也就是某个基类被间接地重复继承了多次。 下图是一个继承图,我们重载了父类的f()函数。   其类继承的源代码如下所示。其中,每个类都有两个变量,一个是整形(4字节

gxj1680的专栏 693

VC中sqlite的使用

在VC中对sqlite的使用,实现数据库大批数据的快速插入,读取数据库中的数据在ListCtrl中显示

[转]C++ 对象的内存布局

转自:http://blog.youkuaiyun.com/haoel/article/details/3081328 前言 07年12月,我写了一篇《C++虚函数表解析》的文章,引起了大家的兴趣。有很多朋友对我的文章留了言,有鼓励我的,有批评我的,还有很多问问题的。我在这里一并对大家的留言表示感谢。这也是我为什么再写一篇续言的原因。因为,在上一篇文章中,我用了的示例都是非常简单的,主要是为了说明一些...

weixin_30412013的博客 113

转:C++ 对象的内存布局

C++ 对象的内存布局

Ssecond的博客 443

C++ 对象的内存布局(上)【转】

C++ 对象的内存布局(上)   陈皓 http://blog.youkuaiyun.com/haoel  【另:自己学习想多看几遍就转载过来,感谢作者,注意版权】  前言   07年12月,我写了一篇《C++虚函数表解析》的文章,引起了大家的兴趣。有很多朋友对我的文章留了言,有鼓励我的,有批评我的,还有很多问问题的。我在这里一并对大家的留言表示感谢。这也是我为什么再写一篇续言的原因。因

Lcz_Ptr的专栏 493

ABB变频器恒压供水故障排查:先查信号链路再决定是否更换

变频器作为工业自动化中的核心设备,广泛应用于恒压供水等场景,其本质是通过改变输出频率调节电机转速,从而稳定管网压力。在实际运行中,自动恒压功能失效的常见原因并非变频器本体损坏,而是压力传感器反馈丢失、AI通道异常、PID参数错乱或通讯中断等外围问题。掌握PID闭环控制原理、模拟量信号测量方法以及故障边界判断思路,能有效缩小排查范围,避免盲目更换设备。本文以ABB ACS510/ACS550为例,介绍从工频模式判断、压力反馈链路检测、面板监视到485通讯验证的系统性排查流程,并结合一控三供水等复杂场景,帮助工

weixin_34110749的博客 357

C++ 对象的内存布局(下)【转】

C++ 对象的内存布局(下)   陈皓 http://blog.youkuaiyun.com/haoel    【另:自己学习想多看几遍就转载过来,感谢作者,注意版权】   重复继承   下面我们再来看看,发生重复继承的情况。所谓重复继承,也就是某个基类被间接地重复继承了多次。   下图是一个继承图,我们重载了父类的f()函数。     其类继承的源代码如下所示。其中,每个类都

Lcz_Ptr的专栏 490

C++ 对象的内存布局(上)-转

http://blog.youkuaiyun.com/haoel/article/details/1948051 目录(?)[-] 前言 对象的影响因素 知识复习 单一的一般继承 多重继承 C++对象的内存布局(上) 陈皓 http://blog.youkuaiyun.com/haoel 点击这里查看下篇>>> 前言 07年12月,我写了一篇《C++虚函数表解析》的文...

weixin_33781606的博客 64

【转】图说C++对象模型:对象内存布局详解

前言文章较长,而且内容相对来说比较枯燥,希望对C++对象的内存布局、虚表指针、虚基类指针等有深入了解的朋友可以慢慢看。 本文的结论都在VS2013上得到验证。不同的编译器在内存布局的细节上可能有所不同。 文章如果有解释不清、解释不通或疏漏的地方,恳请指出。何为C++对象模型?引用《深度探索C++对象模型》这本书中的话:有两个概念可以解释C++对象模型:语言中直接支持面向对象程序设计的部分。 对于

星辰大海,脚踏实地 531

c++对象内存模型【内存布局】(转)

总结:1、按1继承顺序先排布基于每个父类结构。2、该结构包括:基于该父类的虚表、该父类的虚基类表、父类的父类的成员变量、父类的成员变量。3、多重继承且连续继承时,虚函数表按继承顺序排布函数与虚函数。4、而后排布子类的成员变量。5、排布虚基类的虚函数表。6、虚基类的成员变量   #类中的元素 0. 成员变量   1. 成员函数   2. 静态成员变量   3. 静态成员函数   4. 虚函数   5...

weixin_34348111的博客 74

【转】原版C++ 对象的内存布局(上)

转 原版C++ 对象的内存布局(上) Todo 读书笔记 陈皓 http://blog.youkuaiyun.com/haoel 点击这里查看下篇>>> 前言 07年12月,我写了一篇《C++虚函数表解析》的文章,引起了大家的兴趣。有很多朋友对我的文章留了言,有鼓励我的,有批评我的,还有很多问问题的。我在这里一并对大家的留言表示感谢。这也是我为什么再写一篇续言的原因。...

weixin_30246221的博客 62

转 原版 C++ 对象的内存布局(下)

转 原版 C++ 对象的内存布局(下) Todo 读书笔记 陈皓 http://blog.youkuaiyun.com/haoel <<<点击这里查看上篇 重复继承 下面我们再来看看,发生重复继承的情况。所谓重复继承,也就是某个基类被间接地重复继承了多次。 下图是一个继承图,我们重载了父类的f()函数。 其类继承的源代码如下所示。其...

weixin_30246221的博客 67
上一篇: 结构化异常处理(seh) (转)
下一篇: 编译器stack操作
evers
博客等级 码龄24年 7粉丝 4原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值