博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
用函数指针读取并调用虚函数表指向的每个函数
阅读量:6584 次
发布时间:2019-06-24

本文共 1633 字,大约阅读时间需要 5 分钟。

hot3.png

编译器处理虚函数的方法是:给每个对象添加一个隐藏成员——虚函数表(virtual function table,vtbl)[1]。

毫无疑问,下面的代码会用函数指针读取并调用虚函数表指向的每个函数。但是Fun pf=(Fun)*( (int*)*(int*)(&b) +i);究竟是什么意思呢?

#include
using namespace std;class A{public: virtual void g(){cout<<"A g()"<

b是类B的实例,(int*)(&b)表示把b在内存中的地址强制转换为(int*),取得虚函数表的地址。

*(int*)(&b)表示虚函数表中第一个的地址元素,该地址指向b的第一个成员函数。

将其强制转为(int*)后,i为偏移量。我们可以看到i为0、1、2时对应调用的分别是B::g() / A::f() / B::h()

发现[2]中的例子和这里的例子意思完全一样:

class Base {     public:            virtual void f() { cout << "Base::f" << endl; }            virtual void g() { cout << "Base::g" << endl; }            virtual void h() { cout << "Base::h" << endl; }};typedef void(*Fun)(void);int main(){             Base b;            Fun pFun = NULL;            cout << "虚函数表地址:" << (int*)(&b) << endl;            cout << "虚函数表 — 第一个函数地址:" << (int*)*(int*)(&b) << endl;             // Invoke the first virtual function             pFun = (Fun)*((int*)*(int*)(&b));            pFun();}

加偏移量调用其他成员函数

(Fun)*((int*)*(int*)(&b)+0);  // Base::f()(Fun)*((int*)*(int*)(&b)+1);  // Base::g()(Fun)*((int*)*(int*)(&b)+2);  // Base::h()

b的对象模型中包含一个虚函数指针vptr,该指针指向其虚函数表vtbl

在派生过程中,子类覆盖父类虚函数的过程就是替换vtbl中该函数地址的过程。

C++的编译器应该是保证虚函数表的指针存在于对象实例中最前面的位置(这是为了保证取到虚函数表的有最高的性能——如果有多层继承或是多重继承的情况下)。 这意味着我们通过对象实例的地址得到这张虚函数表,然后就可以遍历其中函数指针,并调用相应的函数。 [2]

通过b首地址找到虚函数表的地址图示

到这里终于搞清楚了。

附C++对象模型[3]

class Point{protected:    virtual ostream& print(ostream&os)const;    float _x;    static int _point_count;public:    Point(float xval);    virtual ~Point();    float x() const;    static int PointCount();};

References

  1. c++ primer plus sixth edition

转载于:https://my.oschina.net/SnifferApache/blog/757085

你可能感兴趣的文章
关于使用一个5升容器和一个6升容器量出3升水的一点解决办法
查看>>
我的友情链接
查看>>
我的友情链接
查看>>
我的友情链接
查看>>
get,put,post,delete含义与区别
查看>>
linux命令:rpm软件包管理
查看>>
linux命令:编译安装软件包(举例安装tengine nginx)
查看>>
网络编程方面的知识并不好学
查看>>
yum安装遇到报错整理
查看>>
RedHat Linux 本地yum源的配置
查看>>
Java性能:小建议
查看>>
MySQL server PID file could not be found!-mysql启动错误
查看>>
编写OD插件将IDA中分析出来的函数名导入到OD中
查看>>
STL的fmt函数
查看>>
余弦相似度计算
查看>>
php写的查找和替换一个文件夹下所有的文件内容
查看>>
多线程并发导致CPU100%的一种原因和解决办法
查看>>
事务问题
查看>>
Hibernate的查询分页 by Criteria
查看>>
SNS 背后的技术: 消息流的推拉模式选择
查看>>