C 箴言:确保公开继承模拟“is-a”
2008-02-23 05:24:05来源:互联网 阅读 ()
因此,我一再煞费苦心地向您宣扬,使用 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 }; |
这个继承体系比最初的设计更忠实于我们真正知道的东西。
至此我们还是没有完全做好关于这些鸟的事情,因为对于某些软件系统来说,可能并无需区分能飞的和不能飞的鸟。假如您的应用程式对于鸟喙和鸟翼做了很多处理,而不打算对飞行做什么处理的话,最初的 two-class 的继承体系可能完全适用。他是对“没有一个适用于任何软件的完美设计”这样的事实的一个简单反映。最好的设计依赖于系统究竟期望做什么,无论现在还是未来。假如您的程式对飞行一无所知,而且也不期望以后能知道些什么,那么不分辨能飞和不能飞的鸟可能就是个很完美的设计决策。事实上,他可能比区分他们的设计更为可取,因为您试图模拟的世界中就没有这样一种区分。。
对于如何处理我所说的“任何的鸟能飞,企鹅是鸟,企鹅不能飞,啊……哦……”的问题,更有另一种思想观念。那就是为企鹅重定义 fly 函数,以便让他产生一个运行时错误。
void error(const std::string& msg); // defined elsewhere class Penguin: public Bird { public: virtual void fly() { error("Attempt to make a penguin fly!");} ... }; 标签: 版权申明:本站文章部分自网络,如有侵权,请联系:west999com@outlook.com 上一篇: 对C/C 可变参数表的深层探索
相关文章
IDC资讯: 主机资讯 注册资讯 托管资讯 vps资讯 网站建设 网站运营: 建站经验 策划盈利 搜索优化 网站推广 免费资源 网络编程: Asp.Net编程 Asp编程 Php编程 Xml编程 Access Mssql Mysql 其它 服务器技术: Web服务器 Ftp服务器 Mail服务器 Dns服务器 安全防护 软件技巧: 其它软件 Word Excel Powerpoint Ghost Vista QQ空间 QQ FlashGet 迅雷 网页制作: FrontPages Dreamweaver Javascript css photoshop fireworks Flash 热门词条
最新资讯
热门关注
热门标签
|