直接调用类成员函数地址(用汇编取类成员函数的地址,各VS版本还有所不同)

在C++中,成员函数的指针是个比较特殊的东西。对普通的函数指针来说,可以视为一个地址,在需要的时候可以任意转换并直接调用。但对成员函数来说,常规类型转换是通不过编译的,调用的时候也必须采用特殊的语法。C++专门为成员指针准备了三个运算符: "::*"用于指针的声明,而"->*"和".*"用来调用指针指向的函数。
// Thunk.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"

typedef unsigned int DWORD;

//取类成员函数的地址.vc8版本.可以取私有成员函数地址.
#define GetMemberFuncAddr_VC8(FuncAddr,FuncType)\
{                                                     __asm                                            {                                                    mov eax,offset FuncType                        };                                                __asm                                            {                                                    mov FuncAddr, eax                            };                                            }

//取类成员函数的地址.vc6版本.
template <class ToType, class FromType>
void GetMemberFuncAddr_VC6(ToType& addr,FromType f)
{
    union
    {
        FromType _f;
        ToType   _t;
    }ut;

    ut._f = f;

    addr = ut._t;
}

//调用类成员函数
DWORD CallMemberFunc(int callflag,DWORD funcaddr,void *This,int count,...)
{
    DWORD re;

    if(count>0)//有参数,将参数压入栈.
    {
        __asm
        {
            mov  ecx,count;//参数个数,ecx,循环计数器.

            mov  edx,ecx;
            shl  edx,2;
            add  edx,0x14;  edx = count*4+0x14;

      next:    push  dword ptr[ebp+edx];
            sub   edx,0x4;
            dec   ecx
            jnz   next;
        }
    }

    //处理this指针.
    if(callflag==0) //__thiscall,vc默认的成员函数调用类型.
    {
        __asm mov ecx,This;
    }
    else//__stdcall
    {
        __asm push This;
    }

    __asm//调用函数
    {
        call funcaddr; //call 1.向堆栈中压入下一行程序的地址;2.JMP到call的子程序地址处。
        mov  re,eax;
    }

    return re;
}

//////////////////////////////////////////////////////////////////////////////////////////////////
void test1()//演示c++成员函数指针的用法.
{
   class tt
   {
       public: void foo(int x){ printf("\n %d \n",x); }
   };

   typedef   void (tt::* FUNCTYPE)(int);

    FUNCTYPE ptr = &tt::foo;  //给一个成员函数指针赋值.

    tt a;
    (a.*ptr)(5);   //调用成员函数指针.

    tt *b = new tt;
    (b->*ptr)(6);  //调用成员函数指针.

    delete b;
//    DWORD dwFooAddrPtr= 0;
//    dwFooAddrPtr = (DWORD) &tt::foo;  /* Error C2440 */
//    dwFooAddrPtr = reinterpret_cast<DWORD> (&tt::foo); /* Error C2440 */
}

void test2()//示范如何取成员函数地址.
{
   class tt
   {
       public: void foo(int x){ printf("\n %d \n",x); }
   };

#if _MSC_VER >1200
    DWORD dwAddrPtr1;
    GetMemberFuncAddr_VC8(dwAddrPtr1,tt::foo);
    printf("\n test2 tt::foo %08x",dwAddrPtr1);
#endif

    DWORD dwAddrPtr2;
    GetMemberFuncAddr_VC6(dwAddrPtr2,&tt::foo);
    printf("\n test2 tt::foo %08x",dwAddrPtr2);
}

void test3()//示范如何调用成员函数地址.
{
    class tt
    {
     public:

        void foo(int x,char c,char *s)//没有指定类型,默认是__thiscall.
        {
            printf("\n m_a=%d, %d,%c,%s\n",m_a,x,c,s);
        }

        void __stdcall foo2(int x,char c,char *s)//成员函数指定了__stdcall调用约定.
        {
            printf("\n m_a=%d, %d,%c,%s\n",m_a,x,c,s);
        }

        int m_a;
    };

    typedef  void (__stdcall *FUNCTYPE) (       int,char,char*);//定义对应的非成员函数指针类型,注意指定__stdcall.
    typedef  void (__stdcall *FUNCTYPE2)(void *,int,char,char*);//注意多了一个void *参数.

    tt abc;
    abc.m_a = 123;

    DWORD ptr;
    DWORD This = (DWORD)&abc;

    GetMemberFuncAddr_VC6(ptr,&tt::foo); //取成员函数地址.

    FUNCTYPE fnFooPtr  = (FUNCTYPE) ptr;//将函数地址转化为普通函数的指针. 

    __asm //准备this指针.
    {
        mov ecx, This;
    }

    fnFooPtr(5,‘a‘,"7xyz"); //象普通函数一样调用成员函数的地址.

    GetMemberFuncAddr_VC6(ptr,&tt::foo2); //取成员函数地址.

    FUNCTYPE2 fnFooPtr2 = (FUNCTYPE2) ptr;//将函数地址转化为普通函数的指针. 

    fnFooPtr2(&abc,5,‘a‘,"7xyz"); //象普通函数一样调用成员函数的地址,注意第一个参数是this指针.
}

void test4()//示范通过CallMemberFunc调用成员函数
{
    class tt
    {
     public:

        void foo(int x,char c,char *s)//没有指定类型,默认是__thiscall.
        {
            printf("\n m_a=%d, %d,%c,%s\n",m_a,x,c,s);
        }

        void __stdcall foo2(int x,char c,char *s)//成员函数指定了__stdcall调用约定.
        {
            printf("\n m_a=%d, %d,%c,%s\n",m_a,x,c,s);
        }

        int m_a;
    };

    tt abc;
    abc.m_a = 123;

    DWORD ptr1,ptr2;

    GetMemberFuncAddr_VC6(ptr1,&tt::foo); //取成员函数地址.
    GetMemberFuncAddr_VC6(ptr2,&tt::foo2); //取成员函数地址.

    CallMemberFunc(0,ptr1,&abc,3,5,‘a‘,"7xyz");//第一个参数0,表示采用__thiscall调用.
    CallMemberFunc(1,ptr2,&abc,3,5,‘a‘,"7xyz");//第一个参数1,表示采用非__thiscall调用.
}

void test5()//示范在继承情况下使用函数地址.
{
    class tt1
    {
    public:
                void foo1(){ printf("\n hi, i am in tt1::foo1\n");        }
        virtual void foo3(){ printf("\n hi, i am in tt1::foo3\n");    }
    };

    class tt2 : public tt1
    {
    public:
                void foo2(){ printf("\n hi, i am in tt2::foo2\n");  }
        virtual void foo3(){ printf("\n hi, i am in tt2::foo3\n");    }
    };

    DWORD tt1_foo3,tt2_foo1,tt2_foo2,tt2_foo3;

    GetMemberFuncAddr_VC6(tt1_foo3,&tt1::foo3);
    GetMemberFuncAddr_VC6(tt2_foo1,&tt2::foo1);
    GetMemberFuncAddr_VC6(tt2_foo2,&tt2::foo2);
    GetMemberFuncAddr_VC6(tt2_foo3,&tt2::foo3);

    tt1 x;
    tt2 y;

    CallMemberFunc(0,tt1_foo3,&x,0); // tt1::foo3
    CallMemberFunc(0,tt2_foo1,&x,0); // tt2::foo1 = tt1::foo1
    CallMemberFunc(0,tt2_foo2,&x,0); // tt2::foo2
    CallMemberFunc(0,tt2_foo3,&x,0); // tt2::foo3

    CallMemberFunc(0,tt1_foo3,&y,0); // tt1::foo3
    CallMemberFunc(0,tt2_foo1,&y,0); // tt2::foo1 = tt1::foo1
    CallMemberFunc(0,tt2_foo2,&y,0); // tt2::foo2
    CallMemberFunc(0,tt2_foo3,&y,0); // tt2::foo3
}

int main(int argc, char* argv[])
{
    test1();
    test2();
    test3();
    test4();
    test5();

   return 0;
}

http://download.csdn.net/download/tikycc2/1580557

时间: 2024-08-06 20:47:34

直接调用类成员函数地址(用汇编取类成员函数的地址,各VS版本还有所不同)的相关文章

ifram 取父窗口的URL地址

var url=''; try { url = window.top.document.referrer ; } catch(M) { if (window.parent) { try { url = window.parent.document.referrer; } catch(L) { url = ""; } } } if (url === "") { url = document.referrer; } 以上代码在浏览器中执行过了,能取到地址. ifram

拷贝构造,深度拷贝,关于delete和default相关的操作,explicit,类赋初值,构造函数和析构函数,成员函数和内联函数,关于内存存储,默认参数,静态函数和普通函数,const函数,友元

 1.拷贝构造 //拷贝构造的规则,有两种方式实现初始化. //1.一个是通过在后面:a(x),b(y)的方式实现初始化. //2.第二种初始化的方式是直接在构造方法里面实现初始化. 案例如下: #include<iostream> //如果声明已经定义,边不会生成 class classA { private: int a; int b; public: //拷贝构造的规则,有两种方式实现初始化 //1.一个是通过在后面:a(x),b(y)的方式实现初始化 //2.第二种初始化的方式是直

回调函数中调用类中的非静态成员变量或非静态成员函数

有关这方面的问题,首先说一点: 回调函数必须是静态成员函数或者全局函数来实现回调函数,大概原因是普通的C++成员函数都隐含了一个函数参数,即this指针,C++通过传递this指针给成员函数从而实现函数可以访问类的特定对象的数据成员.由于this指针的原因,使得一个普通成员函数作为回调函数时就会因为隐含的this指针问题使得函数参数个数不匹配,从而导致回调函数编译失败. 基于上面的理论,如何在类中封装回调函数呢? 回调函数只能是全局函数或者静态成员函数,但是由于全局函数会破坏封装性,所以只能用静

思考: 对于一个要重载的运算符而言,什么样的运算符应该用类成员函数重载,什么情况应该用友元函数重载??

还是用一个例子来说明吧 1 #define unsigned int UINT32 2 3 class RMB 4 { 5 public: 6 RMB(UINT32 d, UINT32 c); 7 friend RMB operator +(RMB&, RMB&); 8 friend RMB& operator ++(RMB&); 9 void display() 10 { 11 cout<<(yuan + jf / 100.0)<<endl; 12

在赋值运算符函数中,类的实例能直接访问私有数据成员???

印象中,private的数据成员只能在类的成员函数中使用,无法通过类的对象直接访问!(错误理解) 正确的理解是:在类的成员函数中,可以直接访问私有成员.即只要在该类的成员函数中,无论是直接访问该类的私有数据成员,还是访问某个对象(必选是该类型)的私有数据成员,均是可以的!!! 借鉴网上(http://blog.csdn.net/iaccepted/article/details/34853937 )的说法就是: 实践证明,类(class)私有成员可以被类成员函数访问,不区分成员在哪个实例(ins

再以Circle类为直接基类,派生出一个Cylinder(圆柱体)类,再增加数据成员h(高),,以及求圆柱表面积的成员函数area和求圆柱体积的成员函数volume,实现需要的成员函数,并设计main

/* *Copyright (c) 2016,烟台大学计算机学院 *All rights reserved. *文件名称:main.cpp *作 者:郭辉 *完成时间:2016年5月10日 *版 本 号:v1.0 * *问题描述:再以Circle类为直接基类,派生出一个Cylinder(圆柱体)类,再增加数据成员h(高),,以及求圆柱表面积的成员函数area和求圆柱体积的成员函数volume,实现需要的成员函数,并设计main函数完成测试. *输入描述:无. *程序输出:体积,表面积. */ #

C++成员函数指针错误用法警示(成员函数指针与高性能的C++委托,三篇),附好多评论

今天做一个成绩管理系统的并发引擎,用Qt做的,仿照QtConcurrent搞了个模板基类.这里为了隐藏细节,隔离变化,把并发的东西全部包含在模板基类中.子类只需注册需要并发执行的入口函数即可在单独线程中执行.最终目标是,继承的业务逻辑类外部调用时有两个接口可选,调用syncRun同步执行:调用由引擎自动生成的asyncRun就异步执行.最终自动生成asyncRun的模板基类没能实现,主要原因是mingw对this处理的太有问题了!!原本以为编译器问题,后来才知道成员函数指针和this指针如此特殊

C++ 虚函数&amp;纯虚函数&amp;抽象类&amp;接口&amp;虚基类(转)

http://www.cnblogs.com/fly1988happy/archive/2012/09/25/2701237.html 1. 多态 在面向对象语言中,接口的多种不同实现方式即为多态.多态是指,用父类的指针指向子类的实例(对象),然后通过父类的指针调用实际子类的成员函数. 多态性就是允许将子类类型的指针赋值给父类类型的指针,多态是通过虚函数实现的. 多态可以让父类的指针有“多种形态”,这是一种泛型技术.(所谓泛型技术,就是试图使用不变的代码来实现可变的算法). 2. 虚函数 2.1

【C/C++学院】0823-静态联合编译与动态联合编译/父类指针子类指针释放/虚函数/纯虚函数概念以及虚析构函数/抽象类与纯虚函数以及应用/虚函数原理/虚函数分层以及异质链表/类模板的概念以及应用

静态联合编译与动态联合编译 #include <iostream> #include <stdlib.h> //散列 void go(int num) { } void go(char *str) { } //class //::在一个类中 class A { public: void go(int num) { } void go(char *str) { } }; void main() { ///auto p = go;编译的阶段,静态联编 void(*p1)(char *s