多态---运行时绑定
多态(polymorphism)源于希腊语,意思是“多种形状”。在C++中,它的意思是支持相关的对象具有不同的成员函数(但原型相同),并允许对象与适当的成员函数进行动态时绑定。C++通过覆盖(override)支持这种机制---所有的多态成员函数具有相同的名字,由运行时系统判断哪一个最为合适。当使用继承时就要用到这种机制:有时你无法在编译时分辨所拥有的的对象到底是基类对象还是派生类对象。这个判断并调用正确的函数的过程称为“后期绑定”(late binding)。在成员函数前面加上virtual关键字,可以告诉编译器该成员函数是多态的(也就是虚拟函数)。
在寻常的编译时重载中,函数的原型必须显著不同,这样编译器才能通过查看参数的类型判断需要调用那个函数。但在虚拟函数中,函数的原型必须相同,由运行时系统进行解析,来判断调用哪一个函数。
关键概念:多态
多态是指一个函数或操作符只有一个名字,但它可以用于不同的派生类型。每个对象都实现该操作的一种变型,表现一种最适合自身的行为。它始于覆盖一个名字---对同一个名字进行复用,代表不同对象中的相同概念。多态非常有用,因为它可以给类似的东西取相同的名字。运行时系统在几个名字相同的函数中选择正确的一个进行调用,这就是多态。
给水果类增加一个成员函数,用于为水果去皮(peel)。我们并不研究水果去皮的细节。
#include <stdio.h>
class Fruit{
public:
void peel() {
printf("peeling a base class fruit\n");
}
slice();
juice();
private:
int weight, calories_per_oz;
};
当声明一个水果对象,并向下面这样调用peel()成员函数时:
Fruit banana;
banana.peel();
我们将得到一条信息
peeling a base class fruit
我们知道,可以让苹果类的去皮成员函数与水果类的去皮成员函数同名,因为C++会用覆盖的方法进行处理:
class Apple : public Fruit {
public:
void peel() {
printf("peeling in apple");
}
void make_candy_apple(float weight);
};
让我们声明一个指向水果类的指针,并让他指向一个苹果对象(它继承于水果类),看看当我们试图去皮时会发生什么。
Fruit *p;
p = new Apple;
p->peel();
你会获得下面这条信息
peeling a base class fruit
换句话说,为苹果类量身定做的peel()成员函数并没有被调用,真正调用的是基类的peel成员函数!