欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

公有继承和私有继承

程序员文章站 2022-03-08 19:27:21
...

确保 public inheritance 模拟 "is-a"

使用 C++ 语言进行 object-oriented programming 时唯一最重要规则就是:public inheritance(公开继承)意味着 "is-a"。要让这个规则刻骨铭心。

如果你写了一个 class D ("Derived") 从 class B ("Base") 公开继承,你就是在告诉 C++ 编译器(以及你的代码的读者)每一个类型为 D 的对象也是一个类型为 B 的对象,但是反之则不然。你就是在说 B 描绘了一个比 D 更一般的概念,D 描述了一个比 B 更特殊的概念。你就是在声称一个类型为 B 的对象可以使用的任何地方,一个类型为 D 的对象一样可以使用,因为每一个类型为 D 的对象也就是一个类型为 B 的对象。另一方面,如果你需要一个类型为 D 的对象,一个类型为 B 的对象则不行:每一个 D 都是一个 B,但是反之则不然。

我们从日常的经验知道每一个学生都是一个人,但并不是每一个人都是一个学生。这就是由这个继承体系严格确定的意义。我们期望每一件对于人来说成立的事情——例如,他或她有一个出生日——对于一个学生来说也成立。我们不期望每一件对于学生来说成立的事情——例如,他或她在一所特定的学校注册——对于普通人来说也成立。一个人的概念比一个学生的概念更普通,一个学生一个专门类型的人。

在 C++ 领域中,任何期望引数类型为 Person(或 pointer-to-Person 或 reference-to-Person)的函数都可以接受一个 Student object(或 pointer-to-Student 或 reference-to-Student):

void eat(const Person& p);            // anyone can eat

void study(const Student& s);         // only students study

Person p;                             // p is a Person
Student s;                            // s is a Student

eat(p);                               // fine, p is a Person

eat(s);                               // fine, s is a Student,
                                      // and a Student is-a Person

study(s);                             // fine

study(p);                             // error! p isn't a Student

这一点只对 public inheritance 才成立。只有 Student 以 public 方式从 Person 派生,C++ 才有我所描述的行为。private inheritance 意味着完全不同的其它事情.

is-a 关系并不是能存在于两个 classes 之间的唯一关系。另外两个常见的 inter-class 关系是 "has-a" 和 "is-implemented-in-terms-of"。这些关系将在 Item 38 和 39 中考虑。因为用这些其它重要关系中的一个来不正确地模拟 is-a 而造成的 C++ 设计错误并不罕见,所以你应该确保你理解了这些关系之间的不同,并知道在 C++ 中如何才能用它们做最好的模拟。

Things to Remember

  • public inheritance 意味着 "is-a"。适用于 base classes 的每一件事也适用于 derived classes,因为每一个 derived class object 都是一个 base class object。

谨慎使用 private inheritance(私有继承)

同样的一个例子:

class Person { ... };
class Student: private Person { ... };     // inheritance is now private

void eat(const Person& p);                 // anyone can eat

void study(const Student& s);              // only students study

Person p;                                  // p is a Person
Student s;                                 // s is a Student

eat(p);                                    // fine, p is a Person

eat(s);                                    // error! a Student isn't a Person

很明显,private inheritance(私有继承)不意味着 is-a。那么它意味着什么呢?

“喂!”你说:“在我们得到它的含义之前,我们先看看它的行为。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(公有)的。

行为不过如此。这就给我们带来了含义。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(私有)的原因:它全部都是实现的细节。)利用 Item 34 中提出的条款,private inheritance(私有继承)意味着只有 implementation(实现)应该被继承;interface(接口)应该被忽略。如果 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(是根据……实现的)的事实有一点混乱,因为 Item 38 指出 composition(复合)也有同样的含义。你怎么预先在它们之间做出选择呢?答案很简单:只要你能就用 composition(复合),只有在绝对必要的时候才用 private inheritance(私有继承)。什么时候是绝对必要呢?主要是当 protected members(保护成员)和/或 virtual functions(虚拟函数)掺和进来的时候,另外还有一种与空间相关的极端情况会使天平向 private inheritance(私有继承)倾斜。我们稍后再来操心这种极端情况。毕竟,它只是一种极端情况。

private inheritance(私有继承)更可能在以下情况中成为一种设计策略,当你要处理的两个 classes(类)不具有 is-a(是一个)的关系,而且其中的一个还需要访问另一个的 protected members(保护成员)或需要重定义一个或更多个它的 virtual functions(虚拟函数)。甚至在这种情况下,我们也看到 public inheritance 和 containment 的混合使用通常也能产生你想要的行为,虽然有更大的设计复杂度。谨慎使用 private inheritance(私有继承)意味着在使用它的时候,已经考虑过所有的可选方案,只有它才是你的软件中明确表示两个 classes(类)之间关系的最佳方法。

Things to Remember

  • private inheritance(私有继承)意味着 is-implemented-in-terms of(是根据……实现的)。它通常比 composition(复合)更低级,但当一个 derived class(派生类)需要访问 protected base class members(保护基类成员)或需要重定义 inherited virtual functions(继承来的虚拟函数)时它就是合理的。

  • 与 composition(复合)不同,private inheritance(私有继承)能使 empty base optimization(空基优化)有效。这对于致力于最小化 object sizes(对象大小)的库开发者来说可能是很重要的。

参考:《Effective c++》