在 C++ 中,虚函数是允许在运行时动态绑定的函数。这意味着,如果一个类的函数被声明为虚函数,那么在调用这个函数时,会根据调用该函数的对象的实际类型来决定应该调用哪个版本的函数。
在 C++ 中,这个过程是通过虚函数表(virtual function table,简称 vtable)来实现的。每个类都会有一个 vtable,其中包含了每个虚函数的地址。在类的对象被创建时,会为该对象分配一个指针,指向它所属类的 vtable。
当调用虚函数时,程序会先检查调用对象的 vptr 指针,然后使用该指针查找 vtable 中对应虚函数的地址。最后,程序会跳转到该地址处执行函数的代码。
问题:
有人会问,虚函数不是允许重写吗?如果派生类对基类的虚函数进行了重写,那基类对象调用的虚函数执行时应该跳转到哪里。基类还是派生类的重写处?如果你深刻理解了虚函数的实现原理,这个问题对你来说很简单。答案,他不会跳转到重写处执行,依然会在基类处执行。
重点:虚函数表的实质是一个指针数组,存放的是一个对象的虚函数的入口地址。对于一个派生类来说,他会继承基类的虚函数表,同时增加自己的虚函数入口地址。如果派生类对基类的虚函数进行了重写,那么继承过来的虚函数入口地址将被派生类的重写虚函数入口地址替代。
#include <stdio.h>
class base
{
public:
virtual void draw() {
printf("基类的虚函数\n");
};
virtual void fun()
{
printf("只有基类有fun,派生类不对fun重写\n");
}
};
class son : public base
{
public:
void draw()
{
printf("这是son1重写后的draw函数\n");
}
};
int main()
{
base base1;
base1.draw();//base的虚表指针指向base类的虚函数表,则调用的是base的虚函数,即使draw后面被重写依然执行base的虚函数。
son son1;
son1.draw();
son1.fun();//没有报错,说明派生类继承了基类的虚函数表。
}