1. C++中,成员函数的指针是个比较特殊的东西。对普通的函数指针来说,可以视为一个地址,在需要的时候可以任意转换并直接调用。但对成员函数来说,常规类型转换是通不过编译的,调用的时候也必须采用特殊的语法。C++专门为成员指针准备了三个运算符: "::*"用于指针的声明,而"->*"".*"用来调用指针指向的函数。
  1. // Thunk.cpp : Defines the entry point for the console application.
  2. //
  3.  
  4. #include "stdafx.h"
  5.  
  6. typedef unsigned int DWORD;
  7.  
  8. //取类成员函数的地址.vc8版本.可以取私有成员函数地址.
  9. #define GetMemberFuncAddr_VC8(FuncAddr,FuncType)\
  10. { \
  11. __asm \
  12. { \
  13. mov eax,offset FuncType \
  14. }; \
  15. __asm \
  16. { \
  17. mov FuncAddr, eax \
  18. }; \
  19. }
  20.  
  21. //取类成员函数的地址.vc6版本.
  22. template <class ToType, class FromType>
  23. void GetMemberFuncAddr_VC6(ToType& addr,FromType f)
  24. {
  25. union
  26. {
  27. FromType _f;
  28. ToType _t;
  29. }ut;
  30.  
  31. ut._f = f;
  32.  
  33. addr = ut._t;
  34. }
  35.  
  36. //调用类成员函数
  37. DWORD CallMemberFunc(int callflag,DWORD funcaddr,void *This,int count,...)
  38. {
  39. DWORD re;
  40.  
  41. if(count>)//有参数,将参数压入栈.
  42. {
  43. __asm
  44. {
  45. mov ecx,count;//参数个数,ecx,循环计数器.
  46.  
  47. mov edx,ecx;
  48. shl edx,;
  49. add edx,0x14; edx = count*+0x14;
  50.  
  51. next: push dword ptr[ebp+edx];
  52. sub edx,0x4;
  53. dec ecx
  54. jnz next;
  55. }
  56. }
  57.  
  58. //处理this指针.
  59. if(callflag==) //__thiscall,vc默认的成员函数调用类型.
  60. {
  61. __asm mov ecx,This;
  62. }
  63. else//__stdcall
  64. {
  65. __asm push This;
  66. }
  67.  
  68. __asm//调用函数
  69. {
  70. call funcaddr; //call 1.向堆栈中压入下一行程序的地址;2.JMP到call的子程序地址处。
  71. mov re,eax;
  72. }
  73.  
  74. return re;
  75. }
  76.  
  77. //////////////////////////////////////////////////////////////////////////////////////////////////
  78. void test1()//演示c++成员函数指针的用法.
  79. {
  80. class tt
  81. {
  82. public: void foo(int x){ printf("\n %d \n",x); }
  83. };
  84.  
  85. typedef void (tt::* FUNCTYPE)(int);
  86.  
  87. FUNCTYPE ptr = &tt::foo; //给一个成员函数指针赋值.
  88.  
  89. tt a;
  90. (a.*ptr)(); //调用成员函数指针.
  91.  
  92. tt *b = new tt;
  93. (b->*ptr)(); //调用成员函数指针.
  94.  
  95. delete b;
  96. // DWORD dwFooAddrPtr= 0;
  97. // dwFooAddrPtr = (DWORD) &tt::foo; /* Error C2440 */
  98. // dwFooAddrPtr = reinterpret_cast<DWORD> (&tt::foo); /* Error C2440 */
  99. }
  100.  
  101. void test2()//示范如何取成员函数地址.
  102. {
  103. class tt
  104. {
  105. public: void foo(int x){ printf("\n %d \n",x); }
  106. };
  107.  
  108. #if _MSC_VER >1200
  109. DWORD dwAddrPtr1;
  110. GetMemberFuncAddr_VC8(dwAddrPtr1,tt::foo);
  111. printf("\n test2 tt::foo %08x",dwAddrPtr1);
  112. #endif
  113.  
  114. DWORD dwAddrPtr2;
  115. GetMemberFuncAddr_VC6(dwAddrPtr2,&tt::foo);
  116. printf("\n test2 tt::foo %08x",dwAddrPtr2);
  117. }
  118.  
  119. void test3()//示范如何调用成员函数地址.
  120. {
  121. class tt
  122. {
  123. public:
  124.  
  125. void foo(int x,char c,char *s)//没有指定类型,默认是__thiscall.
  126. {
  127. printf("\n m_a=%d, %d,%c,%s\n",m_a,x,c,s);
  128. }
  129.  
  130. void __stdcall foo2(int x,char c,char *s)//成员函数指定了__stdcall调用约定.
  131. {
  132. printf("\n m_a=%d, %d,%c,%s\n",m_a,x,c,s);
  133. }
  134.  
  135. int m_a;
  136. };
  137.  
  138. typedef void (__stdcall *FUNCTYPE) ( int,char,char*);//定义对应的非成员函数指针类型,注意指定__stdcall.
  139. typedef void (__stdcall *FUNCTYPE2)(void *,int,char,char*);//注意多了一个void *参数.
  140.  
  141. tt abc;
  142. abc.m_a = ;
  143.  
  144. DWORD ptr;
  145. DWORD This = (DWORD)&abc;
  146.  
  147. GetMemberFuncAddr_VC6(ptr,&tt::foo); //取成员函数地址.
  148.  
  149. FUNCTYPE fnFooPtr = (FUNCTYPE) ptr;//将函数地址转化为普通函数的指针.
  150.  
  151. __asm //准备this指针.
  152. {
  153. mov ecx, This;
  154. }
  155.  
  156. fnFooPtr(,'a',"7xyz"); //象普通函数一样调用成员函数的地址.
  157.  
  158. GetMemberFuncAddr_VC6(ptr,&tt::foo2); //取成员函数地址.
  159.  
  160. FUNCTYPE2 fnFooPtr2 = (FUNCTYPE2) ptr;//将函数地址转化为普通函数的指针.
  161.  
  162. fnFooPtr2(&abc,,'a',"7xyz"); //象普通函数一样调用成员函数的地址,注意第一个参数是this指针.
  163. }
  164.  
  165. void test4()//示范通过CallMemberFunc调用成员函数
  166. {
  167. class tt
  168. {
  169. public:
  170.  
  171. void foo(int x,char c,char *s)//没有指定类型,默认是__thiscall.
  172. {
  173. printf("\n m_a=%d, %d,%c,%s\n",m_a,x,c,s);
  174. }
  175.  
  176. void __stdcall foo2(int x,char c,char *s)//成员函数指定了__stdcall调用约定.
  177. {
  178. printf("\n m_a=%d, %d,%c,%s\n",m_a,x,c,s);
  179. }
  180.  
  181. int m_a;
  182. };
  183.  
  184. tt abc;
  185. abc.m_a = ;
  186.  
  187. DWORD ptr1,ptr2;
  188.  
  189. GetMemberFuncAddr_VC6(ptr1,&tt::foo); //取成员函数地址.
  190. GetMemberFuncAddr_VC6(ptr2,&tt::foo2); //取成员函数地址.
  191.  
  192. CallMemberFunc(,ptr1,&abc,,,'a',"7xyz");//第一个参数0,表示采用__thiscall调用.
  193. CallMemberFunc(,ptr2,&abc,,,'a',"7xyz");//第一个参数1,表示采用非__thiscall调用.
  194. }
  195.  
  196. void test5()//示范在继承情况下使用函数地址.
  197. {
  198. class tt1
  199. {
  200. public:
  201. void foo1(){ printf("\n hi, i am in tt1::foo1\n"); }
  202. virtual void foo3(){ printf("\n hi, i am in tt1::foo3\n"); }
  203. };
  204.  
  205. class tt2 : public tt1
  206. {
  207. public:
  208. void foo2(){ printf("\n hi, i am in tt2::foo2\n"); }
  209. virtual void foo3(){ printf("\n hi, i am in tt2::foo3\n"); }
  210. };
  211.  
  212. DWORD tt1_foo3,tt2_foo1,tt2_foo2,tt2_foo3;
  213.  
  214. GetMemberFuncAddr_VC6(tt1_foo3,&tt1::foo3);
  215. GetMemberFuncAddr_VC6(tt2_foo1,&tt2::foo1);
  216. GetMemberFuncAddr_VC6(tt2_foo2,&tt2::foo2);
  217. GetMemberFuncAddr_VC6(tt2_foo3,&tt2::foo3);
  218.  
  219. tt1 x;
  220. tt2 y;
  221.  
  222. CallMemberFunc(,tt1_foo3,&x,); // tt1::foo3
  223. CallMemberFunc(,tt2_foo1,&x,); // tt2::foo1 = tt1::foo1
  224. CallMemberFunc(,tt2_foo2,&x,); // tt2::foo2
  225. CallMemberFunc(,tt2_foo3,&x,); // tt2::foo3
  226.  
  227. CallMemberFunc(,tt1_foo3,&y,); // tt1::foo3
  228. CallMemberFunc(,tt2_foo1,&y,); // tt2::foo1 = tt1::foo1
  229. CallMemberFunc(,tt2_foo2,&y,); // tt2::foo2
  230. CallMemberFunc(,tt2_foo3,&y,); // tt2::foo3
  231. }
  232.  
  233. int main(int argc, char* argv[])
  234. {
  235. test1();
  236. test2();
  237. test3();
  238. test4();
  239. test5();
  240.  
  241. return ;
  242. }

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

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

  1. 从汇编看c++成员函数指针(三)

    前面的从汇编看c++中成员函数指针(一)和从汇编看c++成员函数指针(二)讨论的要么是单一类,要么是普通的多重继承,没有讨论虚拟继承,下面就来看一看,当引入虚拟继承之后,成员函数指针会有什么变化. 下 ...

  2. 从汇编看c++成员函数指针(二)

    下面先看一段c++源码: #include <cstdio> using namespace std; class X { public: virtual int get1() { ; } ...

  3. .static 和const分别怎么用,类里面static和const可以同时修饰成员函数吗。

    static的作用: 对变量: 1.局部变量: 在局部变量之前加上关键字static,局部变量就被定义成为一个局部静态变量. 1)内存中的位置:静态存储区 2)初始化:局部的静态变量只能被初始化一次, ...

  4. c++特性:指向类成员的指针和非类型类模板参数和函数指针返回值 参数推导机制和关联型别

    一.c++允许定义指向类成员的指针,包括类函数成员指针和类数据成员指针 格式如下: class A { public: void func(){printf("This is a funct ...

  5. C++ 友元 (全局函数做友元) (类做友元) (成员函数做友元)

    1 //友元 全局函数做友元 2 /* 3 #include <iostream> 4 #include <string> 5 using namespace std; 6 7 ...

  6. C++ 类 & 对象-C++ 内联函数-C++ this 指针-C++ 类的静态成员

    C++ 内联函数 C++ 内联函数是通常与类一起使用.如果一个函数是内联的,那么在编译时,编译器会把该函数的代码副本放置在每个调用该函数的地方. 对内联函数进行任何修改,都需要重新编译函数的所有客户端 ...

  7. 【转】C++ 虚函数&纯虚函数&抽象类&接口&虚基类

    1. 动态多态 在面向对象语言中,接口的多种不同实现方式即为多态.多态是指,用父类的指针指向子类的实例(对象),然后通过父类的指针调用实际子类的成员函数. 多态性就是允许将子类类型的指针赋值给父类类型 ...

  8. C++ 类的多态三(多态的原理--虚函数指针--子类虚函数指针初始化)

    //多态的原理--虚函数指针--子类虚函数指针初始化 #include<iostream> using namespace std; /* 多态的实现原理(有自己猜想部分) 基础知识: 类 ...

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

    http://www.cnblogs.com/fly1988happy/archive/2012/09/25/2701237.html 1. 多态 在面向对象语言中,接口的多种不同实现方式即为多态.多 ...

随机推荐

  1. DevExpress中GridControl的属性设置

    1.隐藏最上面的GroupPanel gridView1.OptionsView.ShowGroupPanel=false; 2.得到当前选定记录某字段的值 sValue=Table.Rows[gri ...

  2. 第八章: IO库

    一.IO类 1.iostream定义了读写流的基本类型,fstream定义了读写命名文件的类型,sstream定义了读写内存string对象的类型 2.不能拷贝IO对象,因此不能将形参或返回类型设置为 ...

  3. 提高Delphi的编译速度(bpl和bcp)

    delphi的编译速度提高(一) 此博文为原创,转载请注明出处 作者 :二娃 此博文的内容我曾经回答群内和论坛内的网友提问时回答过,现在写第一部分,第二部分,我再给出一个终极的提高速度的方法 我用过d ...

  4. Delphi通过IE窗口句柄获取网页接口(IWebBrowser2) good

    主要用到的是MSAA(Microsoft Active Accessibility) 函数:ObjectFromLResult,该函数在动态链接库 oleacc.dll 中定义. uses SHDoc ...

  5. 强大的DELPHI RTTI–兼谈需要了解多种开发语言

    一月 27th, 2005 by 猛禽 风焱在<“18般武艺”?>中说到他碰上的被多种语言纠缠的问题.我在回复里说: 很多语言只要能看懂几分就行了,没必要每一种都精通 但是如果只会很少的一 ...

  6. DbConnectionFactory 数据库连接

    /** * */package com.sprucetec.dbatch.tmsfee;import java.io.Serializable;import java.sql.Connection;i ...

  7. Unix/Linux环境C编程入门教程(14) Mandriva LinuxCCPP开发环境搭建

    1. Mandriva是目前全球最优秀的Linux发行版之一,稳居于linux排行榜第一梯队. Mandriva公司现在仍然是 这个时候mandriva Linux系统安装完成,基于Mandriva的 ...

  8. 一个Windows C++的线程类实现

    Thread.h [cpp] view plaincopy #ifndef __THREAD_H__ #define __THREAD_H__ #include <string> #inc ...

  9. python访问cloudstack的api接口

    1.CloudStack API 如同 AWS API 一样,CloudStack API 也是基于 Web Service,可以使用任何一种支持 HTTP 调用的语言(例如 Java,python, ...

  10. I Hate It(线段树)

    I Hate It Time Limit: 9000/3000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total S ...