1.虚函数的作用---- 当基类指针指向派生类时,使用这个基类指针调用派生类的函数
多态中派生类和基类之间的特殊关系之一是:基类指针可以在不进行显式类型转换的情况下指向派生类的对象,基类引用可以在不进行显式类型转换的情况下引用派生类对象;
为了区分基类指针调用的函数,是基类的函数,还是派生类的函数,引出了虚函数;
那么,什么是虚函数呢,我们先来看看微软的解释:虚函数是指一个类中你希望重载的成员函数,当你用一个基类指针或引用指向一个继承类对象的时候,你调用一个虚函数,实际调用的是继承类的版本。
这样在使用基类指针指向派生类的对象时,使用基类指针调用相关的函数,就实现对派生类函数的调用;保证调用的相关函数是对象定义时的,相关的类的函数;
2.虚函数调用的实现
有虚函数的类,一定会有一个虚函数表指针vfptr(virtual table pointer,虚函数表指针), 这个vfptr指针会放在类的起始处,并指向这个类的虚函数表(virutal table); VTABLE是该类的所有对象共有的,在定义该类时被初始化;而VPTR则是每个类对象都有独立一份的,且在该类对象被构造时被初始化。当一个对象调用了虚函数,实际的被调用函数通过下面的步骤确定:找到对象的 vptr 指向的 vtbl,然后在 vtbl 中寻找合适的函数指针。
3.纯虚函数
纯虚函数是在类的声明里声明为 = 0 的函数(具体见下面的示例代码)。纯虚函数有如下特点:
- 如果一个类定义了纯虚函数,那么这个类叫虚基类。
- 如果一个类定义了纯虚函数,那么将不能在这个类中实现该函数,而只能在继承该类的类中实现。
- 如果一个类是虚基类,那么这个类不能实例化对象。
- 如果一个类是虚基类,继承它的类并没有实现所有的纯虚函数,那么这个继承它的类也是虚基类。
纯虚函数也能让基类指针所指的子类对象调用到正确的函数。
以下是纯虚函数的例子:
#include <iostream>
using namespace std;
class A {
public:
virtual void foo() = 0; // 声明了一个纯虚函数,A 变成了虚基类,不能实例化对象。
};
class B : public A {
public:
virtual void foo() {
cout << 'B' << endl;
}
};
int main() {
A *p = new B();
p->foo();
return 0;
}
既然说到虚函数和纯虚函数的区别,这里还要说一些虚函数的 FAQ:
- 一个类有虚函数,并不会让它不能实例化一个对象。
- 若父类有一个虚函数,子类没有重写父类的这个函数,那么调用的时候,也会调用到父类的这个函数。