C++编译阶段,没办法知道一个基类的指针或引用所指对象的类型,所以没办法通过这个指针判断调用的虚函数到底是谁的,所以只能通过查找虚函数表来找到函数的入口地址。
一个类,如果有虚函数,那么编译器在编译这个类的时候就会为它添加一个虚函数表,以及指向这个虚函数表的指针。继承这个基类的之类,也会新建一个虚函数表,如果没有重载,那么这个新的虚函数表中的函数指针就被拷贝为父类该函数的地址,否则为新的函数地址。编译器会将这些函数指针在虚函数表中按照基类中该函数出现的次序排列,子类中的虚函数表也将以这种方式排列。
每个有虚函数的类都有一个虚函数表指针pv,当通过指针或引用调用一个虚函数时,先通过pv找到虚函数表,然后根据这个虚函数在虚函数表中的偏移量来找到正确的函数地址,然后再CALL之。
虚函数表是在类之外的,一个类的size不包括虚函数表的大小。而虚函数指针则包含在类中,sizeof一个类则会包含一个虚函数表的指针。
---------------------
作者:lenfien
来源:CSDN
原文:https://blog.csdn.net/lenfien/article/details/51175753?utm_source=copy
版权声明:本文为博主原创文章,转载请附上博文链接!
具体的检查的调用流程如下(c#)
1、当调用一个对象的函数时,系统会直接去检查这个对象申明定义的类,即申明类,看所调用的函数是否为虚函数;
2、如果不是虚函数,那么它就直接执行该函数。而如果有virtual关键字,也就是一个虚函数,那么这个时候它就不会立刻执行该函数了,而是转去检查对象的实例类。
3、在这个实例类里,他会检查这个实例类的定义中是否有重新实现该虚函数(通过override关键字),如果是有,那么OK,它就不会再找了,而马上执行该实例类中的这个重新实现的函数。而如果没有的话,系统就会不停地往上找实例类的父类,并对父类重复刚才在实例类里的检查,直到找到第一个重写了该虚函数的父类为止,然后执行该父类里重写后的函数。