ZC_C++类函数指针_模拟_Delphi类函数指针
ZC: C++的类函数指针 不像 Delphi的类函数指针,前者 需要规定死 是哪个类的函数的指针,后者就不需要 很灵活。
测试环境:
Win7x64
cn_visual_studio_2010_ultimate_x86_dvd_532347.iso
qt-opensource-windows-x86-msvc2010_opengl-5.3.2.exe
暂时的约定(20170105)(基于现在的水平状况)
(1)、所有可能成为函数指针的 类成员函数,去掉 编译器代码优化
(2)、所有 类TClassFuncPtr的子类 的Call()函数 都去掉 编译器代码优化
(3)、所有可能成为函数指针的 类成员函数,都使用 __stdcall 调用约定
(4)、所有 类TClassFuncPtr的子类 的Call()函数 都使用 __stdcall 调用约定
1、测试代码 --> vs2010控制台程序:
1.1、main.cpp
#include <stdio.h> #include <windows.h> #include "ZZ.h" class TClassFuncPtr { public: TClassFuncPtr() { FpObj = NULL; FpFunc = NULL; } protected: void* FpObj; // ZC: 对象指针 void* FpFunc; // ZC: 类函数的 函数地址(统一使用stdcall调用约定,函数传参/调用的时候 方便一点) public: void Set(void *_pObj, void *_pFunc) { FpObj = _pObj; FpFunc = _pFunc; } bool IsValid() { return ( (FpObj != NULL) && (FpFunc != NULL) ); } }; // ZC: 子类 命名规则:“Tcfp_返回值类型_各个传入参数类型()” class Tcfp__ :public TClassFuncPtr { public: void __stdcall Call() { if (IsValid()) { void* pObj = FpObj; void* pFunc = FpFunc; _asm { push pObj // ZC: 直接用FpObj不行,push的值会是0...需要用pObj转一下 call pFunc } } } }; class Tcfp_I_IF :public TClassFuncPtr { public: int __stdcall Call(int _i, float _f) { if (IsValid()) { void* pObj = FpObj; void* pFunc = FpFunc; int iFloat = 0; memcpy(&iFloat, &_f, 4); _asm { push iFloat //ZC: 直接“push _f”不行,需要转一下 push _i push pObj call pFunc } } } }; class Tcfp_CR_IF :public TClassFuncPtr { public: CRtn __stdcall Tcfp_CR_IF::Call(int _i, int _j); }; #pragma optimize( "", off ) CRtn __stdcall Tcfp_CR_IF::Call(int _i, int _j) { if (IsValid()) { _asm { push _j push _i mov eax,dword ptr [ebp+0xC] push eax mov eax,[this] // ZC: 貌似和语句“mov eax,this”是一样的效果... // [eax] ==> FpObj // [eax+4] ==> FpFunc push [eax] call [eax+4] } } } #pragma optimize( "", on ) // ZC: 获取 类函数指针(地址) template<typename dst_type,typename src_type> dst_type pointer_cast(src_type src) { return *static_cast<dst_type*>(static_cast<void*>(&src)); } //#pragma optimize( "gs", off ) void main() { Z01(1, 3); Z02(1, 3); Z03(1, 3); // *** void* p01 = pointer_cast<void*>(&CA::ReturnObj01); void* p02 = pointer_cast<void*>(&CA::ReturnObj02); void* p03 = pointer_cast<void*>(&CA::ReturnObj03); printf("p01 : %08X\n", p01); printf("p02 : %08X\n", p02); printf("p03 : %08X\n", p03); CA a; a.i = 10; printf("&a : %08X\n", &a); void* pA = pointer_cast<void*>(&CA::A); Tcfp_I_IF cfpA; cfpA.Set(&a, pA); int iRtn = cfpA.Call(3, 9); printf("iRtn : %08X, %d\n", iRtn, iRtn); // *** *** *** CRtn cr; printf("&cr : %08X, %d\n", &cr, &cr); //#pragma OPTIMIZE OFF cr = a.ReturnObj01(3, 9); // ZC: 看汇编可以见到,&cr 并不等于 传入的 CRtn指针 的值... 只有在需要用到cr的时候 才会对cr进行设置... //#pragma OPTIMIZE ON //cr.Fi = 3; printf("&cr : %08X, %d\n", &cr, &cr); cr = a.ReturnObj02(3, 9); //#pragma OPTIMIZE ON printf("&cr : %08X, %d\n", &cr, &cr); Tcfp_CR_IF cfp01; cfp01.Set(&a, p03); CRtn cr01; printf("&cr01 : %08X, %d\n", &cr01, &cr01); printf("&cfp01 : %08X, %d\n", &cfp01, &cfp01); cr01 = cfp01.Call(3, 9); printf("cr01.Fi : %08X, %d\n", cr01.Fi, cr01.Fi); system("pause"); }
1.2、ZZ.h
#ifndef ZZZ #define ZZZ //#include <stdio.h> //#include <windows.h> void Z01(int _i, int _j); void Z02(int _i, int _j); void Z03(int _i, int _j); class CRtn { public: int Fi; }; class CA { public: int i; int __stdcall A(int _i, float _j) { int ii = _i + _j * i; return ii * i; } int __stdcall B(int _i, double _j) { int ii = _i + _j * i; return ii * i; } CRtn __stdcall ReturnObj03(int _i, int _j) { CRtn *pRtn = new CRtn(); pRtn->Fi = _i+ _j; return (*pRtn); } // ZC: 这个函数的实现,写在了cpp文件里面,并且使用了编译开关 ==> 它的代码没有被优化 CRtn __stdcall ReturnObj01(int _i, int _j); // ZC: 函数ReturnObj02(...) 虽然加了编译开关,但是看汇编Release版 里面仍然是被优化了... #pragma optimize( "", off ) CRtn __stdcall ReturnObj02(int _i, int _j) { CRtn *pRtn = new CRtn(); pRtn->Fi = 10; return (*pRtn); } #pragma optimize( "", on ) }; #endif // ZZZ
1.3、ZZ.cpp
#include "ZZ.h" #pragma optimize( "", off ) void Z01(int _i, int _j) { _asm { mov eax,eax mov eax,eax mov eax,eax } } #pragma optimize( "", on ) void Z02(int _i, int _j) { _asm { mov ebx,ebx mov ebx,ebx mov ebx,ebx } } void Z03(int _i, int _j) { _asm { mov ecx,ecx mov ecx,ecx mov ecx,ecx } } #pragma optimize( "", off ) CRtn __stdcall CA::ReturnObj01(int _i, int _j) { CRtn *pRtn = new CRtn(); pRtn->Fi = 10; return (*pRtn); } #pragma optimize( "", on )
Z