什么是多态
多态是指某一论域中的一个元素存在多种解释。
多态通常体现为:
- 一名多用:
- 函数名重载
- 操作符重载
- 类属性(范型、generic programming):
- 类属函数:一个函数能对多种类型的数据进行操作;
- 类属类型:一个类型可以描述多种类型的数据。
子类型
对用类型$T$表达的所有程序$P$,当用类型$S$去替换程序$P$中的所有的类型$T$时,程序$P$的功能不变,则称类型$S$是类型$T$的子类型。
- 类型$T$的操作也适合于类型$S$;
- 在需要$T$类型数据的地方可以用$S$类型的数据去替代(类型$S$的值可以赋值或作为函数参数传递给$T$类型变量)。
在C++种,把类看作类型,把以public
方式继承的派生类看作是基类的子类型。
- 对基类对象实施的操作也能作用于派生类对象;
- 在需要基类对象的地方可以用派生类对象去替代(派生类对象可以赋值或作为函数参数传给基类变量)。
面向对象程序设计的多态性
对于具有public
继承关系的两个类,在C++种存在下面的多态:
- 派生类对象的类型既可以是派生类,也可以是基类(对象类型的多态)。
- 基类的指针或引用可以指向或引用基类对象,也可以指向或引用派生类对象(对象标识的多态)。
- 一个可以发送到基类对象的消息,也可以发送到派生类对象,从而可能会得到不同的解释(消息的多态)。
多态性带来了消息的绑定问题:
- 向基类的指针或引用所指向或引用的对象发送消息,将调用(基类还是派生类的)什么成员函数来处理这个消息?
消息的静态绑定
void func1(A &x) {
x.foo(); // 始终调用A::foo
}
void func2(A *p) {
p->foo(); // 始终调用A::foo
}
消息的动态绑定
一般情况下,需要根据标识实际引用(指向)的对象来决定调用基类还是派生类的函数,即采用动态绑定。
在C++种用虚函数来实现动态绑定。
class A {
public:
virtual void foo();
}
虚函数与重定义
虚函数是指加了关键词virtual
的成员函数。虚函数具有两个作用:
- 实现消息的动态绑定;
- 指出基类种可以被派生类重定义的成员函数。
对于基类中的一个虚函数,在派生类中定义的、与之具有相同型构的成员函数是对基类该成员函数的重定义(或称覆盖,override)。
相同的型构是指;
- 派生类中定义的成员函数的名称、参数个数和类型与基类相应成员函数相同;
- 其返回值类型与基类成员函数返回值类型要么相同,要么是基类成员函数返回值类型的
public
派生类。
动态绑定的发生:
- 只有通过基类的指针或引用访问基类的虚函数时才进行动态绑定。
- 基类的构造函数、析构函数对虚函数的调用不进行动态绑定。
对虚函数的其他说明:
- 只有类的成员函数才可以是虚函数,但静态成员函数不能是虚函数。
- 构造函数不能是虚函数,析构函数可以且往往是虚函数。
- 只要在基类中说明了虚函数,在派生类和派生类的派生类等等中,同型构的成员函数都是虚函数(
virtual
可以不写)。
Loading Comments By Disqus