当前位置: 首页 > 文档资料 > C++大学教程 >

10.5 多态性

优质
小牛编辑
132浏览
2023-12-01

C++ 支持多态性。所谓多态性是指:通过继承相关的不同的类,他们的对象能够对同一个函数调用作出不同的响应。例如,如果类 Rectangle 是从类 Quadrilateral 派生出来的,那么类 Rectangle 的对象比类 Quadrilateral 的对象的更具体,对类 Quadfilateral 的对象的操作(如计算周长和面积)也能用在类 Rextangle 的对象上。

多态性是通过虚函数实现的。当通过基类指针(或引用)请求使用虚函数时,C++ 会在与对象关联的派生类中正确地选择重定义的函数。

有时候在基类中定义的非虚函数会在派生类中重新定义。如果用基类指针调用该成员函数,则选择基类版本的成员函数;如果用派生类指针调用该成员函数,则选择派生类版本的成员函数。这不是多态性行为。

下面的例子使用图 9.5 的基类 Employee 和派生类 HourlYWorker:

Employee e, *ePtr = &e;
HourlyWorker h, *hPtr = &h;
ePtr->print(); // call base-class print function
hPtr-> print(); // call derived-class print function
ePtr = &h; // allowable implicit conversion
ePtr->print(); // still calls base-class print

基类 Employee 和派生类 HourlyWorker 都定义了自己的 print 函数。由于这个函数没有声明为virtual,而且签名相同,因此通过Employee指针调用print函数时调用Employee::print() (不管Employee指针指向基类对象还是派生类HourlyWorker对象),而通过HourlyWorker指针调用print函数则调用Worker::print()。派生类也可以调用基类函数,但派生类对象通过派生类对象的指针调用基类print时,函数要显式调用如下:

hPtr-> Employee::print(); // call base—class print function

表示调用基类 print。

使用虚函数和多态性能够使成员函数的调用根据接收到该调用的对象的类型产生不同的动作(但会需要少量执行时的开销)多态性赋予了程序员极大的灵活性。下面几节要举例说明多态性和虚函数的功能。

软件工程视点 10.5
利用虚函数和多态性,程序员可以处理普遍性而让执行环境处理特殊性。即使在不知道一些对象的类型的情况下,程序员也可以命令各种各样的对象表现出适合这些对象妁行为。

软件工程视点 10.6
多态性提高了可扩展性:处理多态性行为的软件可以用与接收消息的对象类型无关的方式编写。因此,不必修改基本系统应可以把能够响应现有消息的新类型的对象添加到系统中。除了实例化新对象的客户代码需要重新编译外,程序无需重新编译。

软件工程视点 10.7
抽象类为类层次结构中的各个成员定义接口。抽象类中包含了要在派生类中定义的纯虚函数,该层次结构中的所有函数都可以通过多态性使用同样的接口。

尽管不能实例化抽象基类的对象,但是可以声明引用抽象基类的指针。当实例化了具体类的对象后,可以用这种指针使派生类对象具有多态操作能力。

下面考虑一个应用多态性和虚函数的例子。一个屏幕管理程序需要显示各种各样的对象,甚至包括在屏幕管理程序编写后又添加到系统中的新类型的对象。系统可能需要显示各种各样的形状,例如正方形、圆形、三角形、矩形等等(每一个类都是基类Shape的派生类)。

屏幕管理程序使用基类指针(指向Shape)来管理要显示的对象。为了能够绘制所有的对象(不管该对象在继承层次结构中的哪一层),管理程序都是使用指向该对象的基类指针并向该对象简单地发送一条draw消息。函数draw在基类Shape中被声明为纯虚函数,并且在每一个派生类中被重新定义,每个对象都知道如何绘制自身。屏幕管理程序不必关心这些细节内容,它只要简单地告诉每个对象进行绘制即可。

多态性特别适合于实现分层的软件系统。例如,在操作系统中各种类型的物理设备彼此之间的操作是不同的,然而从设备读取数据和把数据写入设备的命令在某种程度是统一的。发送给设备驱动程序对象的“写”消息(write函数调用)需要在该设备驱动程序的上下文中具体地解释,并且还要解释设备驱动程序是如何操作该特定类型设备的。但是,write调用本身和对任何其他对象的write调用实际上没有什么区别,都只是把内存中一定数目的字节放在设备中。

面向对象的操作系统可能会用抽象基类为所有设备驱动程序提供合适的接口,然后通过继承抽象基类生成执行所有类似操作的派生类。设备驱动程序所提供的功能(即public接口)在抽象基类中则是以纯虚函数形式出现的,派生类中提供了这些虚函数的实现.已实现的函数能够响应特定类型的设备驱动程序。

利用多态编程,程序可以从类层次的不同层中遍历对象的指针数组。这种数组中的指针都是派生类对象的基类指针。例如,TwoDimensionalshape 类的对象数组可以包含指向派生类 Square、Circle、Triangle、Rectangle 和 Line 等对象的 TwoDimensionalShape * 指针。使用多态编程时,发出一个绘制数组中每个对象的消息即可在屏幕上画出正确的图形。