一种巧妙的取类的虚函数指针的方法

 

        熟悉C++开发的朋友们都知道,每一个包含虚函数的类的对象的前四个字节(32位系统中,以下例子都是在32位系统下)的内存中存放着该对象的虚函数表的指针。虚函数表中依次存放着该对象的每个虚函数的地址。

举个例子:

class TestA

{

public:

       TestA();

       ~TestA();

       virtual void  _cdecl testAFunc();//给该函数加上_cdecl约定是为了保证成员函数的第一个参数this指针可以在该成员函数被调用时压入参数栈

       virtual void  _cdecl testAFunc1(); //理由同上

};

 

TestA::TestA()

{

}

 

TestA::~TestA()

{

}

 

void TestA::testAFunc()

{

       cout<<"testAFunc is called!"<<endl;

}

 

void TestA::testAFunc1()

{

       cout<<"testAFunc1 is called!"<<endl;

}

 

int main()

{

TestA a;

return 0;

}

对于TestA这个类的对象a来说,它在内存中的布局如下:

 

我们可以采用取内存的方法来获得某一个虚函数的指针,方法如下:

typedef  void(*Func) (void);

在main函数中加入以下代码:

Func pFunc = NULL;

pFunc = (Func)*((int *)(*(int*)(&a)) + 0);

pFunc();                    //实际调用的是testAFunc()

pFunc = (Func)*((int *)(*(int*)(&a)) + 1);

pFunc();                    //实际调用的是testAFunc1()

 

输出为:

testAFunc is called!

testAFunc1 is called!

 

但是通过内存来取虚函数指针的方法有点繁琐,稍微一个不留神忘了指针转换或者解除引用就会导致错误,这里,我给大家介绍一种清晰简单的方法来取虚函数。

如上图所示,虚函数表其实是一块连续的内存,里面每个元素(每四个字节)都是一个函数指针,这样的话,我们完全可以把它看做一个结构体,该结构体的每个成员是一个函数指针。

struct TestA_Vtpr

{

       void (*Hook)(TestA *This); //该函数指针的参数列表和返回值必须与类的对应的虚函数的参数列表和返回值一致

       void (*Hook1)(TestA *This);//同上

};    

 

如此这样的话,我们完全可以用以下方式来引用TestA 类的虚函数

(将以下代码加入main函数)

 

TestA a;

TestA_Vtpr **pVtable = (TestA_Vtpr**)(void*)&a;

 TestA_Vtpr *pVtpr = *pVtable;

  pVtpr->Hook(&a);

  pVtpr->Hook1(&a);

   (&a)->testAFunc();  //必须用指向a对象的指针来引用testAFunc,否则不会去查询虚表

   (&a)->testAFunc1(); //同上

 

程序输出如下:

testAFunc is called!

testAFunc1 is called!

testAFunc is called!

testAFunc1 is called!

 

可以看到pVtpr->Hook(&a); 和 (&a)->testAFunc();执行的结果一样的。

亲们,你们明白了么?

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值