不说话,纯膜拜这个分析http://blog.youkuaiyun.com/v_JULY_v/article/details/6446364
尤其是在分析到用vptr来记录存储虚函数的vtbl的时候,如何去通过地址来访问一个函数。
class Base {
private:
virtual void f() { cout << "Base::f" << endl; }
};
class Derive : public Base{
virtual void g(){}
};
typedef void(*Fun)(void);
void main() {
Derive d;
//d.f();
Fun pFun = (Fun)*((int*)*(int*)(&d)+0);
pFun();
}
但是考虑到,每个类的实例都会维护一个virtual table来记录该实例对应的虚函数,而且,如果在派生类中没有重载基类里的虚函数的话,基类的虚函数也会在派生类的virtual table中存在,这样就可以钻空子了------->根据地址来访问这些函数。
Fun pFun = (Fun)*((int*)*(int*)(&d)+0);
1. &d是子类实例的地址,它也就是virtual pointer
2. 将它转换为int*以后,对指针解引用就得到了virtual pointer所指向的virtual table,即 *(int*)(&d)
3. 将将virtual tabel转换为int*的指针,然后通过地址得到tabel里面的不同的虚函数的地址,例如+0就是第一个虚函数,+1就是第二个虚函数,具体第几个的排序规则见上文。
4. 将其解引用得到对应的虚函数
5. 使用函数指针将其强制转换为Fun类型的函数,从而可以让pFun调用。
Over
这里不得不提到一个东西
typedef void(*Fun)(void);
函数指针的typedef和重命名的typedef不太一样
然后Fun就可以被当做一个返回类型为void,参数为void的函数指针类型
引用typedef的百度百科: