测试环境:
本机环境测试时,指针大小为 8 字节,请读者根据实际情况自行判断。
可以使用 sizeof
或者 alignof
判断基本类型的对齐大小。但面对自定义类型的时候,前者就不行了,而后者是专门用来求对齐大小的,所以更推荐后者。
对齐基本规则
先来看两个简单的例子:
class Base1 { //12
char ch1;
int d;
char ch2;
};
由图可知,Base1 的最终大小为:12 字节
class Base2 { //8
int d;
char ch1;
char ch2;
};
同样的计算得到最终大小为:8 字节
class EmptyClass { }; //1
class HaveEmptyClass { //2
EmptyClass a;
EmptyClass b;
};
运行验证得
至于为什么空类大小为 1,首先空类可以被实例化,实例化之后在内存中需要一个地址,如此一来需要占用空间,因此往往会给空类偷偷地加一个字节。
直接上结论吧
class Test { //1
static int a;
void Func();
};
这个类的大小还是 1,相当于空类的情况
class Base { //12, alignof(Base) == 4
char ch1;
int d;
char ch2;
};
class HaveBaseClass { //20
char ch1;
Base b;
char ch2;
};
Base 的对齐大小为 4,可用 alignof(Base)
求出,事实上你也可以自己看出来(该类中数据成员中最大对齐大小即为该类的对齐大小)
如果你没完全理解前面的内容,那就慢慢想,想明白了再看下面的
继承来数据成员顺序是怎么安排的,我们写个代码做测试
class Base {
double d;
char ch1;
char ch2;
};
class Derived : public Base {
char ch3;
};
Derived 的大小:如果 Base 中的数据成员在前,得到的大小应该为 16;如果是 Derived 自己的在前,得到的大小应该为 24
结果:计算的到 Derived 大小为 16
结论:父类数据成员在前,子类数据成员在后
前面提到了普通成员不纳入空间计算,但事实上只有虚函数(包括纯虚函数)才会纳入计算。也就是说,什么静态方法、常成员函数也不纳入空间计算。
虚函数(Virtual Function)是通过一张虚函数表(Virtual Table)来实现的。编译器必需要保证虚函数表的指针存在于对象实例中最前面的位置(这是为了保证正确取到虚函数的偏移量);当然如果出现多个虚函数时,仍然只有一个指向虚表的指针
class Base { //16
char ch1;
virtual void Fun1();
virtual void Fun2();
char ch2;
};
上面 Base 的大小为 16,应证了虚函数表的指针存在于对象实例中最前面的位置的说法。
详细情况请见这一篇文章:C++ 虚函数表,扒过来一张图,还有多重继承和虚函数是否覆盖的情况,建议读者从它的文章中理解清楚。
数据对齐规则
总结:两者相比,取小的为对齐标准
#pragma pack(2)
class Base {
char ch1;
int d;
char ch2;
};
#pragma pack()
结果:sizeof(Base) == 8,alignof(Base) == 2
[1] C++ 类的大小计算 https://blog.csdn.net/fengxinlinux/article/details/72836199
[2] C++ 虚函数表 https://www.jianshu.com/p/7bda11cf4a58