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

来源:互联网 发布:linux 禁用ping 编辑:程序博客网 时间:2024/06/14 21:14

写代码不自然的都会用到有关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 = 40int 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 = 16class CVirtual_Inherit_vitrual_one_memberB :virtual public CVirtual_One_Member{int b;virtual int virtual_funb();};//size = 16class 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)普通,虚拟混合多继承:记住虚继承产生子类自己的虚表和指向父类的偏移指针,闭合虚继承不管父类有多少,只继承一个祖父类虚表。


欢迎大家一起讨论!

0 0