考虑如下代码:
class Person {};
class Student : private Person {};
void eat(const Person& p); // 任何人都会吃
void study(const Student& s); // 只有学生在校学习
Person p; // p是人
Student s; // s是学生
eat(p); // 没问题
eat(s); // 错误!难道学生不是人?
上述eat(s)
错误的原因有两点:
- 如果
classes
之间的继承关系是private
,编译器不会自动将一个derived class
对象转换成一个base class
对象 - 由
private class
继承而来的所有成员,在derived class
中都会变成private
属性,即使它们在base class
中原本是protected
或public
属性
Private
继承意味着is-implemented-in-terms-of
(根据某物实现出),但是条款38指出复合(composition)的意义也是这样,如何取舍?答案是:尽可能使用复合,必要时才使用private 继承
假设我们有一个类Widgets
想知道Wdiget
成员函数多么频繁地被调用,也想知道经过一段时间后调用比例如何变化;
以宁可复用代码,也少些新代码的原则:考虑如下:
class Timer {
public:
explicit Timer(int tickFrequency);
virtual void onTrick() const; //定时器每滴答一次,此函数就被自动调用一次
};
为了让Widget
重新定义Timer
内的virtual
函数,Widget
必须继承自Timer
;但public
继承在此比例并不适当,因为Widget
并不是个Timer
;我们以private
形式继承Timer
:
class Widget : private Timer {
private:
virtual void onTick() const; //查看Widget的数据...等等
};
这是一个好设计,但不值几个钱,因为private
继承绝非必要,如果我们决定以复合取而代之,是可以的:
class Widget{
private:
class WidgetTimer : public Timer {
public:
virtual void onTick() const;
// ...
};
WidgetTimer timer;
};
//待补充…
技术上的原因,C++
裁定凡是独立对象都必须有非零大小,如下代码:
class Empt{}; // 没有数据,所以对象应该不适用任何内存
class HoldsAnInt { //应该只需要一个int空间
private:
int x;
Empty e; //应该不需要任何内存
};
然而上述代码你会发现sizeof(HoldAnInt)
>sizeof(int)
,再大多数编译器中sizeof(Empty)
获得1,因为面对"大小为零之独立对象",通常C++官方勒令默默安插一个char
到空对象内;但是这个约束不适用于derived class
对象内的base class
成分,因为它们并非独立(非附属);如果你继承Empty
,而不是内含一个那种类型的对象:
class HoldsAnInt : private Empty {
private:
int x;
};
几乎可以确定上述代码szieof(HoldsAnInt)
== sizeof(int)
,这就是所谓的EBO(空白基类最优化)