第15章 多态性和虚函数
多态性(在C++中通过虚函数来实现)是面向对象程序设计语言中数据抽象和继承之外的第三个基本特征。
多态性(polymorphism)提供了接口与具体实现之间的另一层隔离,从而将“what”与“how”分离开来。多态性改善了代码的组织性和可读性,同时也使创建的程序具有可扩展性,程序不仅在项目的最初创建期可以“扩展”,而且当在项目需要有新的功能时也能“扩展”。
封装(encapsulation)通过组合特性和行为来生成新的数据类型。访问控制通过使细节数据设为private,将接口从具体实现中分离开来。这类机制对于具有过程化程序设计背景的人来说是非常有意义的。而虚函数则根据类型来处理解耦。在第14章中,我们已经看到,如何继承通过把对象作为它自己的类型或它的基类型来处理。这种能力非常关键,因为它允许很多类型(从同一个基类型派生)被看做是一个类型,一段代码可以同样地工作在所有这些不同类型上。虚函数允许一个类型表达自己与另一个相似类型之间的区别,只要这两个类型都是从同一个基类型派生的。这种区别是通过从基类调用的那些函数行为的不同来表达的。
在本章中,我们将从基本知识开始学习虚函数,为了简单起见,本章所用的例子经过简化,只保留了程序的“虚”性质。
15.1 C++程序员的演变
C程序员可以用三步演变为C++程序员。第一步:简单地把C++作为一个“更好的C”,因为C++要求在使用任何函数之前必须声明它,并且对于如何使用变量有更苛刻的要求。简单地用C++编译器编译C程序常常会发现错误。
第二步:进入“基于对象”的C++。这意味着,很容易看到将数据结构和在它上面活动的函数捆绑在一起的代码组织好处,还可以看到构造函数和析构函数的价值,也许还会看到一些简单的继承。大多数用过C工作的程序员很快就看到这个步骤是有用的,因为无论何时,当他们创建库时,这个步骤都是他们努力要去做的。然而在C++中,将由编译器来帮助我们完成这个步骤。
在基于对象的层面上,我们容易产生错觉,因为我们可以很快成功,并且无需花费太多精力就能得到很多好处。感觉就好像我们正在创建数据类型—制造类和对象,向这些对象发送消息,一切恰到好处并且干净利落。
但是,不要犯傻。如果我们停留在这里,我们就会错失这个语言最重要的部分。这个最重要的部分才是通向真正的面向对象程序设计的飞跃。要做到这一点,只有靠虚函数。
虚函数增强了类型概念,而不是只在结构内部隐蔽地封装代码,所以毫无疑问,对于新的C++程序员来说,这些概念是最困难的。然而,它们也是理解面向对象程序设计的转折点。如果不用虚函数,就等于还不懂得面向对象程序设计(OOP)。
因为虚函数是与类概念紧密联系的,而类是面向对象程序设计的核心,所以在传统的过程型语言中没有类似于虚函数的东西。作为一个过程型程序员,没有什么事物可以帮助他思考虚函数,这与接触该语言的其他大多数功能还有所参照的情况大为不同。过程型语言中的特征可以在算法层上来理解,而虚函数只能从设计的观点来理解。