![]() ![]() |
|
C++箴言:确保公开继承模拟“is-a” | |
作者:佚名 文章来源:不详 点击数 更新时间:2008/4/18 16:05:57 文章录入:杜斌 责任编辑:杜斌 | |
|
|
因此,我一再煞费苦心地向你宣扬,使用 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++ 坚持对 public inheritance 的这一解释。考虑这个例子: class Person {...}; class Student: public Person {...}; 我们从日常的经验知道每一个学生都是一个人,但并不是每一个人都是一个学生。这就是由这个继承体系严格确定的意义。我们期望每一件对于人来说成立的事情——例如,他或她有一个出生日——对于一个学生来说也成立。我们不期望每一件对于学生来说成立的事情——例如,他或她在一所特定的学校注册——对于普通人来说也成立。一个人的概念比一个学生的概念更普通,一个学生一个专门类型的人。 在 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 意味着完全不同的其它事情(参见 Item 39),而 protected inheritance 究竟意味什么使我困惑至今。 public inheritance 和 is-a 等价听起来简单,但有时你的直觉会误导你。例如,企鹅是一种鸟没有问题,而鸟能飞也没有问题。如果我们天真地试图用 C++ 来表达,我们就会得到: class Bird { public: virtual void fly(); // birds can fly ... }; class Penguin:public Bird { // penguins are birds ... }; 突然间我们遇到了麻烦,因为这个继承体系表示企鹅能飞,我们知道这不是真的。发生了什么呢? 在这种情况下,我们成了不严谨的语言——英语的牺牲品。当我们说鸟能飞的时候,我们的意思并非是说所有种类的鸟都能飞,我们不过是说,大体上,鸟有飞的能力。如果我们说得更准确些,我们应该承认有几种不能飞的鸟,并提出如下继承体系,它对事实的模拟要好得多: class Bird { ... // no fly function is declared }; class FlyingBird: public Bird { public: virtual void fly(); ... }; class Penguin: public Bird { ... // no fly function is declared }; |
|
![]() ![]() |