假设一个class不带任何数据,即没有non-static成员变量,没有virtual函数(因为这种函数的存在会为每个对象带来一个vptr),也没有vritual base class,换句话说就是所谓的empty class。你猜这种empty class类对象大小是多少呢?一般人会认为其对象应该不占用任何内存,但是事实上你错了
。
C++裁定凡是独立(非附属)对象都必须有非零大小,不信请看下面实例:
class Empty {};
class HoldsAnInt {
private:
int x;
Empty e;
};
测试后你会发现sizeof(HoldsAnInt) > sizeof(int);说明Empty是要求内存的。
在大多数编译器中sizeof(Empty)为1(g++就是如此),因为面对“大小为0之独立(非附属)对象”,通常C++官方勒令默默安插一个char到空对象内。然而字节对齐可能造成编译器为类似HoldsAnInt这样的class补齐一定的字节,所以HoldsAnInt实际上被放大到足够又存放一个int,在g++中,大小会是8。
前面一直在强调“独立(非附属)”
对象的大小一定不为0,这个约束不适用于derived class对象内的base class成分,因为它们并非独立(非附属)。如果你继承Empty,而不是内含一个那种类型的对象:
class HoldsAnInt : private Empty {
private:
int x;
};
这是sizeof(HoldsAnInt)==sizeof(int)。这就是所谓的EBO(empty base optimization,空白基类最优化)。如果你对空间要求严格,比如:开发公共库、移动端产品,那么EBO,你值得拥有
。但是EBO只对单一继承有效,多重继承的话,请另辟蹊径。
实际上"empty class"并不是真的是empty,虽然其从未拥有non-static成员变量,但是往往内含typedefs、enums、static成员变量,或non-virtual函数。STL就有许多技术用途的empty class,其中内含有用的成员(通常是typedefs),包括base class unary_function和binary_function,这些是“用户自定义之函数对象”通常会继承的class。
当你面对“并不存在is-a关系”的两个class时,而其中一个需要访问另一个的
protected成员,或需要重新定义其一个或多个virtual函数时,private继承极有可能成为正统设计策略。当然一个混合了public继承和复合的设计也能实现这个需求。
需要注意的是:“明智而审慎地使用private继承”是必要的,只有在考虑完所有方案后,发现其仍然是“表现程序内两个class之间关系”的最佳方案时,才使用它。
阅读(3708) | 评论(1) | 转发(1) |