Virtual Table

多重继承下的多态实现

这里详细分析

base2 *b2 = new derive();
b2->f2();

咦,这里不应该是derive::f2()吗,那个non-virtual thunk to derive::f2()是什么鬼?

答案是和this指针强相关。

derive::f2()函数的this指针肯定是derive*类型的,而这里的b2是base2*类型,不能直接调用。

non-virtual thunk to derive::f2()代码其实是两行汇编,它完成出b2指针从base*类型转换成derive*类型的功能,也即地址减去8。

安全性问题

  1. 通过父类型的指针访问子类自己的虚函数

    我们知道,子类没有重载父类的虚函数是一件毫无意义的事情。因为多态也是要基于函数重载的。虽然在上面的图中我们可以看到Base1的虚表中有Derive的虚函数,但我们根本不可能使用下面的语句来调用子类的自有虚函数:

     Base1 *b1 = new Derive();
     b1->f1();  //编译出错

    任何妄图使用父类指针想调用子类中的未覆盖父类的成员函数的行为都会被编译器视为非法,所以,这样的程序根本无法编译通过。

    但在运行时,我们可以通过指针的方式访问虚函数表来达到违反C++语义的行为。

  2. 访问non-public的虚函数

    另外,如果父类的虚函数是private或是protected的,但这些非public的虚函数同样会存在于虚函数表中,所以,我们同样可以使用访问虚函数表的方式来访问这些non-public的虚函数,这是很容易做到的。

class Base {
private:
    virtual void f() { cout << "Base::f" << endl; }
};

class Derive : public Base{};

typedef void(*Fun)(void);

void main() {
    Derive d;
    Fun  pFun = (Fun)*((int*)*(int*)(&d)+0);
    pFun();
}

Reference

Last updated