C++查看类内存分布

在windows下vs中使用的是MSVC的 未公开开关d1reportAllClassLayout

我是在学习类内存分布时找到了这个问题和办法。

C++ 类 内存分布 虚函数 单继承 多继承
重点内容
一、首先看看没有继承情况下类的内存分布:


1.1 定义一个简单的类,没有虚函数。

代码如下:

#include<iostream>
using namespace std;
class Base
{
public:
	int Base_1;
	int Base_2;
public:
	void func1();
};
int main() {
	Base obj_base;
	return 0;
}

vs编译设置:

其中,下面命令中的Base对应要查看的类名Base

/d1 reportSingleClassLayoutBase 

编译完成后,在output窗口有如下内容,可以用于分析内存分布:

1>  class Base	size(8):
1>  	+---
1>   0	| Base_1
1>   4	| Base_2
1>  	+---

从这里可以看到普通类的内存排布方式,成员变量依据声明的顺序进行排列,类内偏移从0开始,普通成员函数不占内存空间。这里没有考虑char等成员变量的字节对齐方式等问题。

1.2 定义一个简单的类,包含虚函数。

#include<iostream>
using namespace std;
class Base
{
public:
int Base_1;
int Base_2;
public:
void func1();
virtual void func2(){};
virtual void func3(){};
};
int main(){
Base obj_base;
return 0;
}

编译,得到的内存分布图如下所示:

1>  class Base	size(12):
1>  	+---
1>   0	| {vfptr}
1>   4	| Base_1
1>   8	| Base_2
1>  	+---
1>
1>  Base::$vftable@:
1>  	| &Base_meta
1>  	|  0
1>   0	| &Base::func2
1>   1	| &Base::func3
1>
1>  Base::func2 this adjustor: 0
1>  Base::func3 this adjustor: 0

从图中可以看出,这个内存结构图分成了两个部分,上面是类的内存分布,下面是虚函数表。这里的编译环境VS2015。从结果可知,编译器是将虚表指针{vfptr}放在类内存的开始处,从图可知其偏移量为0,接着放置类其他成员变量,从图可知,Base_1和Base_2的偏移量分别为4,8。下面部分是类的虚函数表。在&Base_meta后面的0表示,这张虚函数表对应的虚指针{vfptr}在类内存中的分布。接着下面列出类的虚函数,虚函数左边表示虚函数的号。

1.3 单一非虚继承。

#include<iostream>
using namespace std;
class Base
{
public:
    int Base_1;
    int Base_2;
public:
    void func1();
    virtual void func2(){};
    virtual void func3(){};
};
class D :public Base{
public:
    int d_1;
public:
    virtual void func2(){};
};
int main()
{
    return 0;
}

这次使用/d1 reportSingleClassLayoutBase  只能得到与1.2相同的结果:

1>  class Base	size(12):
1>  	+---
1>   0	| {vfptr}
1>   4	| Base_1
1>   8	| Base_2
1>  	+---
1>
1>  Base::$vftable@:
1>  	| &Base_meta
1>  	|  0
1>   0	| &Base::func2
1>   1	| &Base::func3
1>
1>  Base::func2 this adjustor: 0
1>  Base::func3 this adjustor: 0

在vs属性中使用命令行参数替换/d1 reportSingleClassLayoutBase :

/d1 reportAllClassLayout

 运行结果(下面的结果是从很长的输出结果中找到的,输出结果太多,比较难找):

1>  class Base	size(12):
1>  	+---
1>   0	| {vfptr}
1>   4	| Base_1
1>   8	| Base_2
1>  	+---
1>
1>  Base::$vftable@:
1>  	| &Base_meta
1>  	|  0
1>   0	| &Base::func2
1>   1	| &Base::func3
1>
1>  Base::func2 this adjustor: 0
1>  Base::func3 this adjustor: 0
1>
1>  class D	size(16):
1>  	+---
1>   0	| +--- (base class Base)
1>   0	| | {vfptr}
1>   4	| | Base_1
1>   8	| | Base_2
1>  	| +---
1>  12	| d_1
1>  	+---
1>
1>  D::$vftable@:
1>  	| &D_meta
1>  	|  0
1>   0	| &D::func2
1>   1	| &Base::func3
1>
1>  D::func2 this adjustor: 0

分析:
派生类继承了基类的全部,包括虚表指针{vfptr}和其他变量。同时将继承父类的东西放在类内存的开始处,这样,{vfptr}的地址偏移为0,同时派生类也维护一个自己的虚函数表。总结:在非虚继承下:
(1) 派生类会继承基类的全部,包括虚基指针。
(2) 派生类和基类会各自维护一个虚函数表,他们不相同,不是同一张表。从以上结果体现为,基类虚表为Base::$vftable,派生类的虚表为D::vftable。但是他们虚表对应的虚指针是一样的。
 

1.4 单一虚继承。

#include<iostream>
using namespace std;
class Base
{
public:
    int Base_1;
    int Base_2;
public:
    void func1();
    virtual void func2(){};
    virtual void func3(){};
};
class D :virtual public Base{
public:
    int d_1;
public:
    virtual void func2(){};
};
int main()
{
    return 0;
}

运行结果:

1>  class Base	size(12):
1>  	+---
1>   0	| {vfptr}
1>   4	| Base_1
1>   8	| Base_2
1>  	+---
1>
1>  Base::$vftable@:
1>  	| &Base_meta
1>  	|  0
1>   0	| &Base::func2
1>   1	| &Base::func3
1>
1>  Base::func2 this adjustor: 0
1>  Base::func3 this adjustor: 0
1>
1>  class D	size(20):
1>  	+---
1>   0	| {vbptr}
1>   4	| d_1
1>  	+---
1>  	+--- (virtual base Base)
1>   8	| {vfptr}
1>  12	| Base_1
1>  16	| Base_2
1>  	+---
1>
1>  D::$vbtable@:
1>   0	| 0
1>   1	| 8 (Dd(D+0)Base)
1>
1>  D::$vftable@:
1>  	| -8
1>   0	| &D::func2
1>   1	| &Base::func3
1>
1>  D::func2 this adjustor: 8
1>  vbi:	   class  offset o.vbptr  o.vbte fVtorDisp
1>              Base       8       0       4 0
1>

派生类继承了基类的全部,包括虚表指针{vfptr}和其他变量。但是不是将继承父类的东西放在类内存的开始处。在类内存中开始出放置的是自己的虚指针{vbptr},接着自己的成员变量,最后再放置从基类派生下来的数据。此时,派生类有了2个虚指针,一个是自己的虚指针,另一个是从基类派生下来的虚基指针,对应就有2张虚表。各个虚表下面的数字就表示其在类内存中的偏移量。总结:在虚继承下:

  • (1) 派生类会继承基类的全部,包括虚基指针。但是不是将其放在类内存的地址偏移0处。派生类会新生成虚指针,放在类内存地址偏移量为0处。
  • (2) 派生类有2个虚指针,对应有两张虚函数表。
     

参考:C++ 类 内存分布 虚函数 单继承 多继承

参考:C++类内存分布

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

落花逐流水

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值