假如有一个这样的类,没有数据成员和操作(除了本身默认存在的构造函数、复制构造函数、析构函数、copy assignment函数),那么,它能做什么?
class Empty
{
};
一开始我也是以为这样的空类能够有什么作用呢,直到我看了[1],才感叹自己如此肤浅(所以也建议你去看:)
先假设我们有个很傲娇的类,它不希望通过构造函数生成,也不希望别的对象对它赋值。很不巧,如果我们没有在类中声明复制构造函数或者赋值操作符,那么编译器会为我们默认生成。
那么如何防止这样的事情发生呢?
将复制构造函数和赋值操作符声明为私有
像这样:
class SomeClass
{
private:
SomeClass(const SomeClass&);
SomeClass& operator=(const SomeClass&);
...
};
那么当有以下操作都是非法的:
//假如有SomeClass s;
SomeClass scopy(s);//error
s = scopy;//error
然而更加高级的做法是定义一个空类,将空类的复制构造函数和赋值操作符声明为私有,然后让SomeClass继承它。像这样:
class Empty
{
protected:
Empty(){} //允许derived class调用
~Empty(){}
private:
Empty(const Empty&); //阻止了copying
Empty& operator = (const Empty&);
};
class SomeClass: private Empty
{
...
};
当有人尝试拷贝SomeClass 对象时,编译器会试着去调用base class,也就是Empty 的 copy 构造函数,然后因为private 而告终。
另一个方面,一个空类没有数据成员,理应是不占内存的。
但是sizeof运用于空类的话,会发现空类大小为1。
引用[1]中的原话:
然而,由于技术上的理由,C++裁定凡是独立(非附属)对象都必须有非零大小
通常C++ 官方勒令默默安插一个char 到空对象内。
但,这个约束并不适用于derived class对象内的base class成分,因为它们并非独立。
也就是说,如下:
class SomeClass1
{
private:
int x;
Empty e;
};
class SomeClass2: public Empty
{
private:
int x;
}:
sizeof(SomeClass1) == 8;
sizeof(SomeClass2) == 4;
Someclass1 占用内存肯定不等于一个int,而且因为内存对齐的原因,结果占用内存达到了8;
这是所谓的EBO(empty base optimization:空白基类最优化)
[参考资料]
[1] [1] Scott Meyers 著, 侯捷译. Effective C++ 中文版: 改善程序技术与设计思维的 55 个有效做法[M]. 电子工业出版社, 2011.(条款06:若不想使用编译器自动生成的函数,就该明确拒绝、条款39:明确而审慎地使用private 继承)