• 覆盖构成条件和多态构成条件是相同的,覆盖是一种函数间的表现关系,而多态描述的是函数的一种性质,二者所描述的其实是同一种语法现象。
  • 覆盖首先要求有继承关系,其次是要求构成继承关系的两个类中必须具有相同函数签名的成员函数,并且这两个成员函数必须是虚成员函数
  • 具备这三个条件后,派生类中的虚成员函数会覆盖基类中相同签名的虚成员函数。如果我们通过基类指针或引用来调用虚成员函数,则会形成多态。
#include<iostream>
using namespace std;
class base
{
public :
virtual void vir1(){cout<<"base::vir1"<<endl;}
virtual void vir2(){cout<<"base::vir2"<<endl;}
virtual ~base(){cout<<"base::destruct"<<endl;}
};
class derived : public base
{
public:
void vir1(){cout<<"derived::vir1"<<endl;}
void vir2(){cout<<"derived::vir2"<<endl;}
virtual ~derived(){cout<<"derived::destruct"<<endl;}
};
int main()
{
base * p;
p = new derived;
p->vir1();
p->vir2();
delete p;
return 0;
}

本例中,base 类和 derived 类构成继承关系,在这两个类中成员函数 vir1() 和 vir2() 同名,并且这两个同名函数都被声明为了虚函数。如此一来就构成了函数覆盖,派生类中的 vir1() 函数覆盖了基类中的 vir1() 函数,派生类中的 vir2() 函数覆盖了基类中的 vir2() 函数。在主函数中,通过基类指针调用 vir1() 和 vir2() 虚函数,构成多态,这两个函数的运行为运行期绑定。

函数覆盖属于运行期绑定,但是要注意:如果函数不是虚函数,则无论采用什么方法调用函数均为编译期绑定。如果我们将例 6 中的基类中的两个 virtual 关键字去掉,则主函数中调用 vir1() 和 vir2() 函数属于编译期绑定,无论 p 指向的是派生类对象或者是基类对象,执行的都将会是基类的 vir1() 和 vir2() 函数。