当前位置: 首页 > news >正文

C++虚继承内存布局

C++菱形继承内存布局

编译器:Visual Studio 2019
关于如何查看内存布局

B

class B
{
public:B(): _ib(10), _cb('B'){cout << "B()" << endl;}B(int ib, char cb): _ib(ib), _cb(cb){cout << "B(int,char)" << endl;}virtualvoid f(){cout << "B::f()" << endl;}virtualvoid Bf(){cout << "B::Bf()" << endl;}
private:int _ib;char _cb;
};

B内存布局图:size = 12
虚函数指针(4B)
int型数据成员(4B)
char型数据成员(4B,3B用于对齐)

1>class B	size(12):
1>	+---
1> 0	| {vfptr}
1> 4	| _ib
1> 8	| _cb
1>  	| <alignment member> (size=3)
1>	+---
1>B::$vftable@:
1>	| &B_meta
1>	|  0
1> 0	| &B::f
1> 1	| &B::Bf
1>B::f this adjustor: 0
1>B::Bf this adjustor: 0

B1

class B1
: virtual public B
{
public:B1(): _ib1(100), _cb1('1'){}B1(int ib, char ic, int ib1, char cb1): B(ib, ic), _ib1(ib1), _cb1(cb1){cout << "B1(int,char,int,char)" << endl;}virtualvoid f(){cout << "B1::f()" << endl;}virtualvoid f1(){cout << "B1::f1()" << endl;}virtualvoid Bf1(){cout << "B1::Bf1()" << endl;}
private:int _ib1;char _cb1;
};

B1内存布局图:size = 32
虚函数指针(4B)
虚基表指针(4B)
int型数据成员(4B)
char型数据成员(4B,3B用于对齐)
vtordisp(4B)
从基类B继承来的12B

1>class B1	size(32):
1>	+---
1> 0	| {vfptr}
1> 4	| {vbptr}
1> 8	| _ib1
1>12	| _cb1
1>  	| <alignment member> (size=3)
1>	+---
1>16	| (vtordisp for vbase B)
1>	+--- (virtual base B)
1>20	| {vfptr}
1>24	| _ib
1>28	| _cb
1>  	| <alignment member> (size=3)
1>	+---
1>B1::$vftable@B1@:
1>	| &B1_meta
1>	|  0
1> 0	| &B1::f1
1> 1	| &B1::Bf1
1>B1::$vbtable@:
1> 0	| -4
1> 1	| 16 (B1d(B1+4)B)
1>B1::$vftable@B@:
1>	| -20
1> 0	| &(vtordisp) B1::f
1> 1	| &B::Bf
1>B1::f this adjustor: 20
1>B1::f1 this adjustor: 0
1>B1::Bf1 this adjustor: 0
1>vbi:	   class  offset o.vbptr  o.vbte fVtorDisp
1>               B      20       4       4 1

B2

class B2: virtual public B
{
public:B2(): _ib2(1000), _cb2('2'){}B2(int ib, char ic, int ib2, char cb2): B(ib, ic), _ib2(ib2), _cb2(cb2){cout << "B2(int,char,int,char)" << endl;}virtualvoid f(){cout << "B2::f()" << endl;}virtualvoid f2(){cout << "B2::f2()" << endl;}virtualvoid Bf2(){cout << "B2::Bf2()" << endl;}
private:int _ib2;char _cb2;
};

B2内存布局图:size = 32
虚函数指针(4B)
虚基表指针(4B)
int型数据成员(4B)
char型数据成员(4B,3B用于对齐)
vtordisp(4B)
从基类B继承来的12B

1>class B2	size(32):
1>	+---
1> 0	| {vfptr}
1> 4	| {vbptr}
1> 8	| _ib2
1>12	| _cb2
1>  	| <alignment member> (size=3)
1>	+---
1>16	| (vtordisp for vbase B)
1>	+--- (virtual base B)
1>20	| {vfptr}
1>24	| _ib
1>28	| _cb
1>  	| <alignment member> (size=3)
1>	+---
1>B2::$vftable@B2@:
1>	| &B2_meta
1>	|  0
1> 0	| &B2::f2
1> 1	| &B2::Bf2
1>B2::$vbtable@:
1> 0	| -4
1> 1	| 16 (B2d(B2+4)B)
1>B2::$vftable@B@:
1>	| -20
1> 0	| &(vtordisp) B2::f
1> 1	| &B::Bf
1>B2::f this adjustor: 20
1>B2::f2 this adjustor: 0
1>B2::Bf2 this adjustor: 0
1>vbi:	   class  offset o.vbptr  o.vbte fVtorDisp
1>               B      20       4       4 1

D

class D: public B1, public B2
{
public:D(): _id(10000), _cd('3'){}D(int ib, char cb, int ib1, char cb1, int ib2, char cb2, int id, char cd): B1(ib, cb, ib1, cb1), B2(ib, cb, ib2, cb2), B(ib, cb), _id(id), _cd(cd){cout << "D(...)" << endl;}virtualvoid f(){cout << "D::f()" << endl;}virtualvoid f1(){cout << "D::f1()" << endl;}virtualvoid f2(){cout << "D::f2()" << endl;}virtualvoid Df(){cout << "D::Df()" << endl;}
private:int _id;char _cd;
};

D内存布局图:size = 56
从基类B1继承的16B
从基类B2继承的16B
int型数据成员(4B)
char型数据成员(4B,3B用于对齐)
vtordisp(4B)
从基类B继承的12B

虚基表指针存储的内容是什么?(以B2的vbptr为例,地址为20)
① 虚基表指针与子类对象首地址的偏移量(-4,子类B2首地址为16)
② 虚基表指针到虚基类部分的偏移量(24,虚基类B首地址为44)

多重继承:
① 每个基类都有自己的虚函数表:B1,B2
② 派生类如果有自己的虚函数,会被加入到第一个虚函数表中:D自己的虚函数Df被加入到B1的虚函数表中
③ 内存布局中,基类的布局按照被声明时的顺序排列:先B1后B2,如果反过来,内存布局会改变,D自己的虚函数会被加入到B2的虚函数表中(可自己实践)
④ 派生类会覆盖基类的虚函数,只有第一个虚函数表中存放的是真实的被覆盖的函数的地址,其它虚函数表中存放的并不是真实的地址,而是一条跳转指令

1>class D	size(56):
1>	+---
1> 0	| +--- (base class B1)
1> 0	| | {vfptr}
1> 4	| | {vbptr}
1> 8	| | _ib1
1>12	| | _cb1
1>  	| | <alignment member> (size=3)
1>	| +---
1>16	| +--- (base class B2)
1>16	| | {vfptr}
1>20	| | {vbptr}
1>24	| | _ib2
1>28	| | _cb2
1>  	| | <alignment member> (size=3)
1>	| +---
1>32	| _id
1>36	| _cd
1>  	| <alignment member> (size=3)
1>	+---
1>40	| (vtordisp for vbase B)
1>	+--- (virtual base B)
1>44	| {vfptr}
1>48	| _ib
1>52	| _cb
1>  	| <alignment member> (size=3)
1>	+---
1>D::$vftable@B1@:
1>	| &D_meta
1>	|  0
1> 0	| &D::f1
1> 1	| &B1::Bf1
1> 2	| &D::Df //将D中的虚函数加在B1虚函数表中?
1>D::$vftable@B2@:
1>	| -16
1> 0	| &D::f2
1> 1	| &B2::Bf2
1>D::$vbtable@B1@:
1> 0	| -4 //虚基表指针与子类对象首地址的偏移量
1> 1	| 40 (Dd(B1+4)B) //虚基表指针到虚基类部分的偏移量
1>D::$vbtable@B2@:
1> 0	| -4
1> 1	| 24 (Dd(B2+4)B)
1>D::$vftable@B@:
1>	| -44
1> 0	| &(vtordisp) D::f
1> 1	| &B::Bf
1>D::f this adjustor: 44
1>D::f1 this adjustor: 0
1>D::f2 this adjustor: 16
1>D::Df this adjustor: 0
1>vbi:	   class  offset o.vbptr  o.vbte fVtorDisp
1>               B      44       4       4 1
http://www.lryc.cn/news/8998.html

相关文章:

  • IO模型--从BIO、NIO、AIO到内核select、poll、epoll剖析
  • Zebec完成BNB Chain以及Near链上协议部署,多链化进程加速
  • wpscan常见的使用方法
  • Tree 底层源码实现(二叉树、递归、迭代)
  • 家政服务小程序实战教程13-接入客服
  • 大白话高并发(三)
  • vue全家桶(四)前端工程化
  • 超螺旋滑模控制(STA)
  • NX二次开发编译时dll自动数字签名及拷贝
  • 教你如何搭建人事OA-薪资管理系统,demo可分享
  • ChIP-seq 分析:Mapped 数据可视化(4)
  • Jenkins 基于Kubernetes 弹性构建池
  • 经典算法题---链表奇偶重排(好题)双指针系列
  • 数据仓库实战
  • GPT系列:GPT, GPT-2, GPT-3精简总结 (模型结构+训练范式+实验)
  • ASE12N65SE-ASEMI高压MOS管ASE12N65SE
  • centos8防火墙命令配置(开放端口)
  • Instagram营销教程_编程入门自学教程_菜鸟教程-免费教程分享
  • HTTP Code含义
  • Elasticsearch:Security API 介绍
  • springmvc考研交流平台 java ssm mysql
  • 2.15 vue3 day01 setup ref setup的参数 prop slot插槽 自定义事件通信
  • CentOs7更新Yum源
  • 【C/C++】VS2019下C++生成DLL并且成功调用(金针菇般细)
  • 如何重新安装安卓手机系统
  • ArcGIS API for JavaScript 4.15系列(7)——Dojo中的Ajax请求操作
  • 智慧校园电子班牌系统
  • 软考高项——第五章进度管理
  • 基于springboot+bootstrap+mysql+redis搭建一套完整的权限架构【二】【整合springSecurity】
  • 字节6面,成功唬住面试官拿了27K,软件测试面试也没有传说中那么难吧....