C++中的虚函数和虚函数表
在上面一篇博客中 https://www.cnblogs.com/wphl-27/p/18111083,提到了虚函数,纯虚函数
这篇博客我想继续进一步来说一下虚函数和虚函数表
在C++中,每一个含有虚函数的类,编译器都会为它啊做出一个虚函数表(通常叫做 vtable), 这个虚函数表里面的每个元素都是函数指针,每个元素(函数指针)指向一个虚函数的地址.
除此之外,编译器还会为这种含有虚函数的类,添加上一个成员变量,这个成员变量是一个指向它的虚函数表的指针(通常称为 vptr). 我们来看下面这个例子
class Class1 { public : data1; data2; memfunc(); virtual vfunc1(); virtual vfunc2(); virtual vfunc3(); };
这个Class1 ,它里面包括3个虚函数,我们来看看这个类在内存中空间
我们可以看到,它自动增加了一个成员变量 vptr, 这是一个指针,可以看到它指向的是Class1的虚函数表vtable, 这个虚函数表中有3个元素,是3个函数指针,它们分别指向Class1的三个虚函数的地址
当有一个派生类来继承基类Class1时,它会继承基类的虚函数表(以及其他所有可以继承的成员), 派生类中同样有这个新增的成员变量 vptr, 它同样指向派生类的虚函数表.
当我们在派生类中改写某个虚函数时,它继承下来的虚函数表就受了影响,虚函数表中对应的这个虚函数的函数指针,指向的地址将不再是基类的函数地址,而是改写后的派生类中该虚函数的函数地址
我们来看个例子:
class Class2 : public Class1 { public : data3; memfunc(); virtual vfunc2(); };
它的内存空间是这样的
可以看到Class2的虚函数表vtable中,它的第二个函数指针指向的是Class2::vfunc2(), 而不再是基类的Class1::vfunc1(), 也就是说它存的是Class2函数自己的重写后的vfun2函数的地址
所以一个「指向Class1所生对象」的指针,所调用的 vfunc2 就是 Class1::vfunc2,而一个「指向Class2 所生对象」的指针,所调用的 vfunc2 就是 Class2::vfunc2。
这也就是说我们在上篇博客
C++中基类指针指向派生类对象 中提到的动态联编机制。 动态联编,在运行时,而不是编译时,会根据虚函数表,来做出正确的选择