C++中的多态实际上就是让父类指针拥有多种形态。
C++使用虚函数来实现多态。
虚函数的原理就是在对象创建的同时创建了一张虚表。并且把虚表的地址放到对象的最顶部。那么父类指针肯定就可以获取到这个虚表。如果调用虚函数,则会直接通过虚表调用。
假设我们有两个类,
1 | class people { |
people有两个virtual函数,boy类只overwrite了一个。
我们先看一下底层是怎样调用虚函数的:

我们可以看到虚函数的call用到了call [edx]而不是直接跳到一个固定的地方。这里就是间接跳转。
edx里面存放的就是虚表的地址值,[edx]就是虚表里面第一个地址。所以b这个对象调用了虚表里面的第一个函数。
同样的,如果我们调用p对象的laugh()函数,也是调用p对象虚表里面的第一个位置。
所以有了第一个结论:
虚表中的函数地址个数与virtual函数的个数一样,并且与virtual函数的位置对应(比如我这个例子中laugh()对应虚表第一个函数地址, piss()对应虚表第二个位置)
那么我们继续深入,看一下b和p这两个对象的虚表有什么区别:
因为对象最顶上的第一个4bytes存放的就是虚表的地址,我是再Stack中创建的对象,直接在栈中查看,如下:

得到p的虚表地址为00b59c5c; b的虚表地址为00b59d5c。
p的虚表如下:

p的虚表为00b51505,00b5151e。
b的虚表如下:

b的虚表为: 00b5150f, 00b5151e。
我们可以看到p和b的虚表都有两个值,分别对应laugh()和piss()。因为boy类重写了laugh()函数,所以boy类的虚表中第一个地址是自己重写的laugh(),而people类的第一个地址是people类中的laugh()地址。
因为boy类没有重写piss()。所以boy类的第二个地址就是people类的piss()地址。
所以第二个结论就是:
如果子类没有overwrite父类的virtual函数,那么子类虚表中对应的地址与最近的父类的对应地址相同。
Conclusion:
virtual function的实现方法如下:
