浅谈C++类大小以及内存布局

写代码不自然的都会用到有关Class的内容,现在我来浅谈一下关于Class大小以及内存布局的一些问题。

                                                                                                          

(1)空类

class CEmpty
{

};//size = 1

注: 为什么时间大小为0编译器(vs13)却要定义成1呢?

C++标准中规定,"No object shall have the same address in memory as any other variable",试想一下,我们如果定义一个CEmpty对象数组,那么如果类大小为0,所有生成的对象在内存中都指向了同一个地址,我们无法通过索引Index对对象进行选择,所以类大小为0显然违背标准。

class CEmpty_MemberFunc
{
	void print()
	{
		std::cout << "CEmpty_MemberFunc's print";
	}
};//size = 1

注:类成员函数并不会影响类大小

class CEmpty_STATIC_Member
{
	static int nA;
};//size = 1

注:static成员变量存放区域为全局数据区,在类生成对象之前进行初始化,并不影响类大小

class CEmpty_STATIC_Function
{
	static int static_print()
	{
		std::cout << "CEmpty_STATIC_Function's static_print";
	}
};//size = 1

注:static函数表明函数的作用范围,并不会影响类大小

(2)简单类

class CTwo_Member
{
	int a;
	char b;
};//size = 8 if pack(4) 


注:成员变量a 占 4字节 ,b 字节对齐,故b占4字节 
class CDeclaration_Struct_And_Two_Member
{
	struct Struct
	{
		int a1;
		char a2;
		short a3;
		long long a7;
		char a4;
		long long a5;
		char a6;
	};
	int a;
	char b;
};//size =8

注:可见结构体只声明并不会影响内存大小

class CStruct_And_Two_Member
{
	struct Struct
	{
		int a1;
		char a2;
		short a3;
		long long a7;
		char a4;
		long long a5;
		char a6;
	}S1; //size = 40
	int a;
	char b;
};size = 48


可见结构体对齐大小不影响类成员对齐大小,结构体大小影响类大小

(3)简单继承类

class CInherit_empty : public CEmpty
{
	int a;
};//size = 4

注:继承空类,类的大小是继承类大小

(4)含虚拟函数的类

class CVirtual_One_Member
{
     virtual int virtual_fun1();
     virtual int virtual_fun2();
};//size = 4 

注:类的虚函数保存在虚函数表vfptr中,类大小为4

(5)含虚拟函数类的继承

class CInherit_vitrual_one_member : public CVirtual_One_Member
{
	int virtual_fun1();
	int virtual_fun2();
	virtual int virtual_fun3();
};//size = 4 虽然没有virtual关键字,但是和基类函数相同,默认为virtual

注:可见vfun1,vfun2依旧是虚函数,vfun3保存在vfptr中

(6)虚继承

class CVirtual_Inherit_vitrual_one_member :virtual public CVirtual_One_Member
{
	virtual int virtual_fun3();
};//size = 12

注:由布局信息可见:虚继承会产生一个自己的vfptrc存储新产生的vfun3,产生一个vbptr指向虚基类偏移量,加上继承一个基类虚函数表,所以类大小12

(7)闭合虚继承

如图:

class CVirtual_Inherit_vitrual_one_memberA :virtual public CVirtual_One_Member
{
	int a;
	virtual int virtual_funa();
};//size = 16

class CVirtual_Inherit_vitrual_one_memberB :virtual public CVirtual_One_Member
{
	int b;
	virtual int virtual_funb();
};//size = 16

class CInherit_vitrual_one_memberAB :public CVirtual_Inherit_vitrual_one_memberA,public CVirtual_Inherit_vitrual_one_memberB
{
	int c;
	virtual int virtual_func();
};//size = 32

AB:

注:由图可知虚继承基类放在了内存布局最后,指向同一空间,A,B产生了两个不同的vfptr以及不同的vbptr,func存放在A的vfptr中(根据继承顺序,放在A),AB类大小=A类大小(16)+B类大小(16)+AB类成员大小(4) - 重复的(AB指向同一基类)基类大小(4) = 32


混合多继承(略)

                                                                                                          

总结:

(1)普通单继承:子类如果有虚函数,父类如果有虚表,子类沿用父类虚表,没有则产生虚表。

(2)普通多继承:子类如果有虚函数则继承第一个父类的虚表,有多少个有虚函数的父类就有多少个虚表。

(3)虚拟单继承:子类有虚函数产生自己的虚表,并产生vbptr指向父虚基类偏移量,如果父虚基类有虚函数也继承父类的虚表。

(4)多重虚继承:子类如有虚函数则产生自己的虚表,虚拟继承于同一祖父类的父类则只有同一个祖父类虚表。

(5)普通,虚拟混合多继承:记住虚继承产生子类自己的虚表和指向父类的偏移指针,闭合虚继承不管父类有多少,只继承一个祖父类虚表。


欢迎大家一起讨论!

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值