多态性与前面提到的数据封装和继承性共同构成了面向对象程序设计的三个重要机制。
1.静态联编与动态联编
由于函数重载的存在,当程序中出现调用同名函数时,编译器会根据函数的参数类型、个数决定调用执行哪一个同名函数的代码,这种把一个函数的调用与适当的函数实现代码联系在一起的过程,叫做联编。根据联编的实现阶段的不同,可将其分为静态联编和动态联编两种。
静态联编是在程序编译阶段确定一个函数调用与函数实现代码间的对应关系,这种对应关系确定下来后,在程序运行过程中就根据这个对应关系去调用执行相应的函数代码,并且这种对应关系在程序运行过程中始终保持不变。
而动态联编是在编译阶段不能决定执行哪个同名的被调函数,只在程序运行过程中根据需要处理的对象类型来决定执行哪个类的成员函数。
2.多态性
所谓多态性就是指同样的消息被类的不同对象接收时导致的完全不同的行为的一种现象。这里所说的消息即对类的成员函数的调用。
函数的重载可以实现多态性,但这里要讲的多态性是通过虚函数来实现的,而虚函数又必须存在于继承的环境下。
C++语言支持两种类型的多态:一种是编译时的多态(静态多态),另一种是运行时的多态(动态多态)。在编译时的多态是通过静态联编实现的,而在运行时的多态则是通过动态联编实现的。
3.虚函数
声明虚函数的方法是在基类中的成员函数原型前加上关键字virtual.格式如下:
class 类名{
……
virtual 类型 函数名(参数表);
……
};
当一个类的成员函数声明为虚函数后,这就意味着该成员函数在派生类中可能有不同的实现,也就是说,该函数在派生类中可能需要定义与其基类虚函数原型相同的函数。
虚函数是动态联编的基础,当用基类类型的指针或引用的方法指向不同派生类对象时,系统会在程序运行中根据所指向对象的不同自动选择适当的函数,从而实现了运行时的多态性。
当通过基类指针或引用标识对象并调用成员函数时,由于基类指针可以指向该基类的不同派生类对象,因此存在需要动态联编的可能性,但具体是否使用动态联编,还要看所调用的是否是虚函数。
虚函数可以在一个或多个派生类中被重新定义,但它要求在派生类中重新定义时必须与基类中的函数原型完全相同,包括函数名、返回值类型、参数个数和参数类型的顺序。
只有类的成员函数才能声明为虚函数,但类的构造函数以及全局函数和静态成员函数不能声明为虚函数。
4.用基类指针指向公有派生类对象
指向基类的指针自然可以指向其公有派生类的对象。但是,由于基类指针本身的类型并没有改变,因此,基类指针仅能访问派生类中的基类部分。
5.纯虚函数与抽象类
在定义一个表达抽象概念的基类时,有时可能会无法给出某些成员函数的具体实现。这时,就可以将这些函数声明为纯虚函数。
纯需函数的声明格式如下:
virtual 类型 函数名(参数表)=0;
声明了纯虚函数的基类只是用于继承,仅作为一个接口,具体功能在其派生类中实现。
声明了纯虚函数的类,称为抽象类。抽象类只能用作基类来派生新类,而不能用来创建对象。