写代码不自然的都会用到有关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)
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)普通,虚拟混合多继承:记住虚继承产生子类自己的虚表和指向父类的偏移指针,闭合虚继承不管父类有多少,只继承一个祖父类虚表。
欢迎大家一起讨论!