考虑一个类(或对象)的sizeof运算结果时,有一些细节需要注意。比如空类,是否sizeof结果就为0;成员函数(虚/实)会占多大空间等。
1. 空类的大小
像如下,定义一个空类:
class VoidClass
{
};
用sizeof(VoidClass)计算VoidClass的大小,结果会是:1
虽然空类本身没有任何空间需求,但是为了实例化,必须要让其对象占用一定的空间(这里分配了1个字节),否则会有两个对象地址相同的情况出现,如:
VoidClass a, b;
显然 &a != &b; 但如果编译器只分配了0个字节给其对象,会造成其对象和邻近定义的其它变量无法区分。
对于只有成员函数,没有成员变量的类:
class Other
{
public:
void SayBye() {cout << "bye" << endl;}
};
sizeof(Other)的结果为 1
sizeof的参数是类型时,计算的是该类型的变量所占的空间。成员函数存放在代码段中,sizeof不统计这部分大小。
2. 包含虚函数的类
下面定义了一个只包含虚析构函数的类:class VirtualBase
{
public:
virtual ~VirtualBase() {}
};
在64位机器,sizeof(VirtualBase)的结果是: 8
如果类中有虚函数,编译器会在数据段中存放一个虚表,在类中会生成一个成员变量----虚指针(占用1个字空间,64位环境是8字节)。
class DerivedA : public VirtualBase
{
public:
virtual ~DerivedA() {}
virtual void SayHi() {cout << "hi" << endl;}
};
class DerivedB : public VirtualBase
{
public:
virtual ~DerivedB() {}
virtual void SayHi() {cout << "hi" << endl;}
private:
int b;
};
class DerivedC : public VirtualBase
{
public:
virtual ~DerivedC() {}
void SayBye() {cout << "bye" << endl;}
private:
int b;
};
class DerivedD : public VirtualBase
{
public:
virtual ~DerivedD() {}
virtual void SayHi() {cout << "hi" << endl;}
void SayBye() {cout << "bye" << endl;}
private:
int b;
int c;
};
其中,A只有一个虚析构函数和一个虚函数,B在A基础上增加了一个int成员变量,C把B的虚函数变成了实函数,D在C基础上又增加了一个int成员变量。
A的大小是8,占空间的是虚指针;
B的大小是16,虚指针8字节,int4字节,另外补充了4个填充字节,用于对齐。这里的填充说明一件事,我们这里使用的编译器,把虚指针放到了对象的其它成员变量的后面。
C和B一样大。
D的大小仍然是16,这里不需要填充空白字节对齐了。
3. 完整代码
class VoidClass
{
};
class VirtualBase
{
public:
virtual ~VirtualBase() {}
};
class DerivedA : public VirtualBase
{
public:
virtual ~DerivedA() {}
virtual void SayHi() {cout << "hi" << endl;}
};
class DerivedE : public VirtualBase
{
public:
void SayHi() {cout << "hi" << endl;}
};
class DerivedB : public VirtualBase
{
public:
virtual ~DerivedB() {}
virtual void SayHi() {cout << "hi" << endl;}
private:
int b;
};
class DerivedC : public VirtualBase
{
public:
virtual ~DerivedC() {}
void SayBye() {cout << "bye" << endl;}
private:
int b;
};
class DerivedD : public VirtualBase
{
public:
virtual ~DerivedD() {}
virtual void SayHi() {cout << "hi" << endl;}
void SayBye() {cout << "bye" << endl;}
private:
int b;
int c;
};
class Other
{
public:
void SayBye() {cout << "bye" << endl;}
};
为了方便观察sizeof结果,定义了如下的宏:
#define SHOW_SIZE(t) cout << #t << " size: " << sizeof(t) << endl;
执行下面的main函数:
int main()
{
SHOW_SIZE(VoidClass);
SHOW_SIZE(VirtualBase);
SHOW_SIZE(DerivedA);
SHOW_SIZE(DerivedB);
SHOW_SIZE(DerivedC);
SHOW_SIZE(DerivedD);
}
得到的结果为:
VoidClass size: 1
VirtualBase size: 8
DerivedA size: 8
DerivedB size: 16
DerivedC size: 16
DerivedD size: 16