虚函数 以及 由此用到的函数指针

来源:互联网 发布:如何注册网络经纪人 编辑:程序博客网 时间:2024/05/16 12:51

不说话,纯膜拜这个分析http://blog.csdn.net/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函数是private的,那么派生类其实是不能去访问基类的private函数的,因此,代码里的注释掉的那一行会报错,private函数f()对于d来说不可访问。

但是考虑到,每个类的实例都会维护一个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的百度百科:

typedef int (*PF) (const char *, const char *);
这个声明引入了 PF 类型作为函数指针的同义字,该函数有两个 const char * 类型的参数以及一个 int 类型的返回值。如果要使用下列形式的函数声明,那么上述这个 typedef 是不可或缺的:
PF Register(PF pf);
Register() 的参数是一个 PF 类型的回调函数,返回某个函数的地址,其署名与先前注册的名字相同。做一次深呼吸。下面我展示一下如果不用 typedef,我们是如何实现这个声明的:
int (*Register (int (*pf)(const char *, const char *)))
(const char *, const char *);
很少有程序员理解它是什么意思,更不用说这种费解的代码所带来的出错风险了。显然,这里使用 typedef 不是一种特权,而是一种必需。



0 0
原创粉丝点击