在基类中可能会存在virtual函数,那么当派生类继承了基类的话,一般都是希望派生类重新定义继承来的virtual函数。如果派生类没有定义某个虚函数,则使用基类定义的版本。C++中的函数调用默认不使用动态绑定。要触发动态绑定需要满足两个条件:(1)只有指定为虚函数的成员函数才能进行动态绑定,成员函数默认为非虚函数时,不进行动态绑定。(2)必须通过基类类型的引用或指针进行函数调用。
class fruit {
public:
fruit(){}
virtual ~fruit(){}
virtual void printName(fruit f) { cout << "this is a base item" << endl; }
virtual void print() { cout << "this is fruit" << endl; }
};
class apple :public fruit
{
public:
apple(){}
~apple(){}
virtual void print() { cout << "this is an apple!" << endl; }
virtual void printName(fruit& f)
{
f.print();
}
};
int main()
{
fruit myfavourite;
apple *Apple=new apple;
Apple->printName(myfavourite);
Apple->printName(*Apple);//动态绑定
}
运行结果如下:
虽然上面的printName()函数的形参是基类fruit&类型的,但是最后运行的结果却是一个调用基类的printName()函数,另一个调用派生类的printName()函数。在第一个调用中形参f是和基类fruit对象绑定在一起的,所以在printName()函数的内部调用的是基类的print()函数;而第二个调用中形参f是和派生类apple对象绑定在一起的,所以在printName()函数的内部调用的是派生类的print()函数。其实这里面存在小细节,因为每个基类对象都是派生类对象的子对象,所以第二个调用传入的是派生类的对象,但是其实是把派生类的基类子对象和该形参f进行绑定的。编译器在编译阶段是无法判断出调用的是基类的函数还是派生类的函数,因为派生类中具有基类的部分,所以只有当运行的时候才知道调用的是哪个版本的函数。
通过引用或指针调用虚函数时,编译器将生成代码,在运行的时候才能够确定出调用哪个函数,被调用的是与动态类型相对应的函数。