在《C++箴言:确保公开继承模拟“is-a”》一文中论述了 C++ 将 public inheritance(公有继承)视为一个 is-a 关系。当给定一个 hierarchy(继承体系),其中有一个 class Student 从一个 class Person 公有继承,当为一个函数调用的成功而有必要时,需要将 Students 隐式转型为 Persons,它通过向编译器展示来做到这一点。用 private inheritance(私有继承)代替 public inheritance(公有继承)把这个例子的一部分重做一下是值得的: 5(3O/C{?~
=p+y$
class Person { ... }; !%iHJwS#
class Student: private Person { ... }; // inheritance is now private E
TT46%Y
(W
~K1]
void eat(const Person& p); // anyone can eat ZK5nN9`
ZJYn[\]
void study(const Student& s); // only students study Qp>leEs]+6
CU'JvVe3
Person p; // p is a Person l~c[} wv
Student s; // s is a Student Zxa.x?:?n
t`Kbm''d[
eat(p); // fine, p is a Person [#PE'i4
@Z jT_
eat(s); // error! a Student isn't a Person lQn"
6o1
|9CikLX)7
很明显,private inheritance(私有继承)不意味着 is-a。那么它意味着什么呢? I//=C6
g.lTNQm$u
“喂!”你说:“在我们得到它的含义之前,我们先看看它的行为。private inheritance(私有继承)有怎样的行为呢?”好吧,支配 private inheritance(私有继承)的第一个规则你只能从动作中看到:与 public inheritance(公有继承)对照,如果 classes(类)之间的 inheritance relationship(继承关系)是 private(私有)的,编译器通常不会将一个 derived class object(派生类对象)(诸如 Student)转型为一个 base class object(基类对象)(诸如 Person)。这就是为什么为 object(对象)s 调用 eat 会失败。第二个规则是从一个 private base class(私有基类)继承的 members(成员)会成为 derived class(派生类)的 private members(私有成员),即使它们在 base class(基类)中是 protected(保护)的或 public(公有)的。 *'%V}R[>
%6UF%dbYH`
行为不过如此。这就给我们带来了含义。private inheritance(私有继承)意味着 is-implemented-in-terms-of(是根据……实现的)。如果你使 class(类)D 从 class(类)B 私有继承,你这样做是因为你对于利用在 class(类)B 中才可用的某些特性感兴趣,而不是因为在 types(类型)B 和 types(类型)D 的 objects(对象)之间有什么概念上的关系。同样地,private inheritance(私有继承)纯粹是一种实现技术。(这也就是为什么你从一个 private base class(私有基类)继承的每一件东西都在你的 class(类)中变成 private(私有)的原因:它全部都是实现的细节。)利用《接口继承和实现继承》中提出的条款,private inheritance(私有继承)意味着只有 implementation(实现)应该被继承;interface(接口)应该被忽略。 d*gAL<M7E
i5 '&u:
如果 D 从 B 私有继承,它就意味着 D objects are implemented in terms of B objects(D 对象是根据 B 对象实现的),没有更多了。private inheritance(私有继承)在 software design(软件设计)期间没有任何意义,只在 software implementation(软件实现)期间才有。 private inheritance(私有继承)意味着 is-implemented-in-terms-of(是根据……实现的)的事实有一点混乱,正如《通过composition模拟“has-a”》一文中所指出的 composition(复合)也有同样的含义。你怎么预先在它们之间做出选择呢?答案很简单:只要你能就用 composition(复合),只有在绝对必要的时候才用 private inheritance(私有继承)。什么时候是绝对必要呢?主要是当 protected members(保护成员)和/或 virtual functions(虚拟函数)掺和进来的时候,另外还有一种与空间相关的极端情况会使天平向 private inheritance(私有继承)倾斜。我们稍后再来操心这种极端情况。 1Kg0y71"
f7Gn$E|/r;
毕竟,它只是一种极端情况。 假设我们工作在一个包含 Widgets 的应用程序上,而且我们认为我们需要更好地理解 Widgets 是怎样被使用的。例如,我们不仅要知道 Widget member functions(成员函数)被调用的频度,还要知道 call ratios(调用率)随着时间的流逝如何变化。带有清晰的执行阶段的程序在不同的执行阶段可以有不同的行为侧重。例如,一个编译器在解析阶段对函数的使用与优化和代码生成阶段就有很大的不同。 $><