我们先谈谈单继承的情况:
1.编译器能否识别多态,看是否有virtual关键字,如果有,那么在声明对象的时候,内存会分配一个vptr关键字和一个vptb表,其中vptr指向vptb表。
假定某一个虚函数f(),放在vptb的slot(2)中,一个虚函数g()凡在slot(3)中,当基类声明了一个虚函数,并且有子类继承基类的时候会出现二种情况:
1.基类的虚函数f()被子类重写,此时,子类有一个VPTR指针指向vptb表,在子类的vptb表的slot(2)中,也有一个f()函数,不过此时的f()函数类型是子类的。
2.基类的虚函数f()没有被子类重写,此时,子类有一个VPTR指针指向vptb表,在子类的vptb表的slot(2)中,也有一个f()函数,不过此时的f()函数类型是基类的。
那么有以上2点,在多态实现编译期就可以知道虚函数的偏移地址,唯一不知道的就是,是哪一个VPTR表的虚函数,那么这个问题会在执行期搞定。
例如
ptr->f();
会被转化为
(*ptr->vptb[2])(ptr);
有vptr[2]我们已经知道了去执行哪一个函数,唯一不知道的就是,哪一个虚函数表的vptr[2].
在编译器的执行期,会告诉编译器去执行哪一个虚函数表,那么此时就完成了多态。
多继承的情况:
多继承的情况下,派生类内部的情况比较复杂,主要是:
1.产生了n个vptb表,其中n-1个是额外的vptb表;
2.第一个vptb是主要的表格,继承着第一个基类的vptb。
3.后面n-1个是次要的表格。
当基类base1的指针指向派生类的时候,那么和单继承的情况是一样的。
当基类base2的指针指向派生类的时候,那么会有指针地址的调整,像前调整(sizeof(base1))个单位。这些都是在执行期完成的。