一个面向对象的系统常常要求一组具有相同基本语义的方法能在同一接口下为不同的对象服务,这就是多态性(polymorphism).
通俗的来说,多态就是在一个方法在不同基类的派生类中表现出不同的实现形式。比如,定义水果类为基类,苹果,梨,香蕉为派生类,在水果类,苹果,梨,香蕉中都有一个计算蒸发率的成员函数,但是,在苹果,梨,香蕉中,因为他们是不同水果,有不同蒸发率,所以,虽然同样是计算蒸发率,但是计算的方法不同,这种用不同方法计算不同派生类蒸发率的方式就是多态。
在C++中,多态分为:编译时的多态性和运行时的多态性。其中,编译时的多态性通过重载和模板来实现,其实现的机制为一种静态绑定的机制;而运行时的多态性通过虚函数来实现,其实现的方式为一种动态绑定的方式。
先来看一种静态绑定机制的多态:
#include<iostream> using namespace std; class People //人类 { public: print() {cout<<"我是人类"<<endl;} }; class Singer:People //歌手类 { public: print() {cout<<"我是歌手:Jay!"<<endl;} }; class Programmer:People //程序猿类 { public: print() {cout<<"我是一个程序猿:Vac!"<<endl;} }; int main() { People p; Singer Jay; //歌手Jay Programmer Vac; //程序猿Vac p.print(); cout<<endl; Jay.print(); cout<<endl; Vac.print(); cout<<endl; return 0; }
结果如我们所预料的那样:
Singer Jay和ProgrammerVac分别调用本类中定义的print()函数,输出的结果也是我们想要的。但是这种调用是建立在静态绑定机制上的,不具备多态特征。
PS:
多态调用是借助于指向基类的指针或引用的调用。
下面来看一下用指针访问的情况:
#include<iostream>
using namespace std;
class People //人类
{
public:
print() {cout<<"我是人类"<<endl;}
};
class Singer:public People //歌手类
{
public:
print() {cout<<"我是歌手:Jay!"<<endl;}
};
class Programmer:public People //程序猿类
{
public:
print() {cout<<"我是一个程序猿:Vac!"<<endl;}
};
int main()
{
People p;
Singer Jay; //歌手Jay
Programmer Vac; //程序猿Vac
People * Pp=&p;
People * PJay=&Jay;
People * PVac=&Vac;
Pp->print();
PJay->print();
PVac->print();
return 0;
}
运行时出现如下结果:
这显然不是我们想要得到的,指针所执行的函数都是基类的print()函数,根本没有实现多态。
解决方法:
只要在声明基类People的时候,将print()声明为虚函数,则在用指针或引用访问print()函数的时候,调用的是指针所指向的重定义的函数,而不是指向原来基类中的函数。
总结虚函数:
指向基类的指针在操作它的多态类对象时,会根据不同的类对象,调用其相应的函数,这个函数就是虚函数。