10.3 虚函数
假定一组形状类(如 Circle、Trriangle、Rectangle 和 Square 等等)都是从基类Shape派生出来的。在面向对象的程序设计中,我们可能要使每一个这样的类都能够绘制其自身形状。尽管每个类都有它自己draw函数,但是绘制每种形状的 draw 函数却是大不相同的。
当需要绘制形状时,不管它是什么形状,把它作为基类Shape的对象处理是再好不过的。然后,我们只需要简单地调用基类 Shape 的函数 draw,并让程序动态地确定(即在执行时确定)使用哪个派生类的draw函数。
为了使这种行为可行,我们把基类中的函数 draw 声明为虚函数,然后在每个派生类中重新定义 draw 使之能够绘制合适的形状。虚函数的声明方法是在基类的函数原型前加上关键字 virtual。例如,基类 Shape 中可能出现:
virtual void draw() const;
上述原型声明函数draw是不取参数也不返回数值的常量函数,而且是个虚函数。
软件工程视点 10.2
一旦一个函数被声明为虚函数,即使重新定义类时没有声明虚函数,那么它从该点之后的继承层次结构中都是虚函数。
编程技巧 10.1
虽然函数在类层次结构的高层中声明为虚函数会使它在低层隐式地成为虚函数,但有些程序员为了提高程序的清晰性更喜欢在每一层中显式地声明这些虚函数。
软件工程视点 10.3
没有定义虚函数的派生类简单地继承其直接基类的虚函数。
如果在基类中将函数 draw 声明为 virtual,然后用基类指针或引用指明派生类对象并使用该指针调用 draw 函数(如 shapePtr->draw()),则程序会动态地(即在运行时)选择该派生类的 draw 函数,这称为动态关联(见10.6和10.9节的实例研究)。
如果用名字和圆点成员选择运算符引用一个特定的对象来调用虚函数(如 squareObject.draw()),则被调用虚函数是在编译时确定的(称为静态关联),调用的虚函数也就是为该特定对象的类定义(或继承该特定对象类)的函数。