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 = ;
memcpy(&iFloat, &_f, );
_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+]
}
}
}
#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(, );
Z02(, );
Z03(, ); // *** 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 = ;
printf("&a : %08X\n", &a); void* pA = pointer_cast<void*>(&CA::A);
Tcfp_I_IF cfpA;
cfpA.Set(&a, pA);
int iRtn = cfpA.Call(, );
printf("iRtn : %08X, %d\n", iRtn, iRtn); // *** *** *** CRtn cr;
printf("&cr : %08X, %d\n", &cr, &cr);
//#pragma OPTIMIZE OFF
cr = a.ReturnObj01(, ); // ZC: 看汇编可以见到,&cr 并不等于 传入的 CRtn指针 的值... 只有在需要用到cr的时候 才会对cr进行设置...
//#pragma OPTIMIZE ON
//cr.Fi = 3;
printf("&cr : %08X, %d\n", &cr, &cr); cr = a.ReturnObj02(, );
//#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(, );
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 = ;
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 = ;
return (*pRtn);
}
#pragma optimize( "", on )
Z
ZC_C++类函数指针_模拟_Delphi类函数指针的更多相关文章
- ZC_C++类函数指针_模拟_Delphi类函数指针_Qt例子
qt-opensource-windows-x86-msvc2010_opengl-5.3.2.exe ZC: “const QString” 作传入参数的时候,不太会弄... 貌似 还是在进行构建等 ...
- C++第四篇--重载_指针_引用
C++第四篇--重载_指针_引用 1. 基础知识 重载:函数名相同,根据参数不同(类型.数量.顺序不同)调用同名函数 指针和引用:引用就是别名,引用时必须初始化,引用你定义的变量. int a; in ...
- ca71a_c++_指向函数的指针_通过指针调用函数txwtech
/*ca71a_c++_指向函数的指针_通过指针调用函数用typedef简化函数指针的定义简化前: bool(*pf)(const string&, const string &); ...
- c语言中较常见的由内存分配引起的错误_内存越界_内存未初始化_内存太小_结构体隐含指针
1.指针没有指向一块合法的内存 定义了指针变量,但是没有为指针分配内存,即指针没有指向一块合法的内浅显的例子就不举了,这里举几个比较隐蔽的例子. 1.1结构体成员指针未初始化 struct stude ...
- C语言_初步了解一下指针
指针的基本概念 在计算机中,所有的数据都是存放在存储器中的. 一般把存储器中的一个字节称为一个内存单元, 不同的数据类型所占用的内存单元数不等,如整型量占2个单元,字符量占1个单元等.为了正确地访问这 ...
- 零基础逆向工程24_C++_01_类_this指针_继承本质_多层继承
1 类内的成员函数和普通函数的对比 1.1 主要是从参数传递.压栈顺序.堆栈平衡来总结. 1.参数传递:成员函数多传一个this指针 2.压栈顺序:成员函数会将this指针压栈,在函数调用取出 3.堆 ...
- 【c实现,vc6调试通过】给出一字符串指针,计算出字符串指针中单词数
#include <stdio.h> /* 给出一字符串指针,计算出字符串指针中单词数, 单词不包括'.',',',';','?','_','"',由0-9数字或26个字母组成 ...
- Qt 智能指针学习(7种指针)
Qt 智能指针学习 转载自:http://blog.csdn.net/dbzhang800/article/details/6403285 从内存泄露开始? 很简单的入门程序,应该比较熟悉吧 ^_^ ...
- 不可或缺 Windows Native (18) - C++: this 指针, 对象数组, 对象和指针, const 对象, const 指针和指向 const 对象的指针, const 对象的引用
[源码下载] 不可或缺 Windows Native (18) - C++: this 指针, 对象数组, 对象和指针, const 对象, const 指针和指向 const 对象的指针, con ...
随机推荐
- python ddt 实现数据驱动一
ddt 是第三方模块,需安装, pip install ddt DDT包含类的装饰器ddt和两个方法装饰器data(直接输入测试数据) 通常情况下,data中的数据按照一个参数传递给测试用例,如果da ...
- Java接口多线程并发测试 (一)
本文为作者原创,禁止转载,违者必究法律责任!!! 本文为作者原创,禁止转载,违者必究法律责任!!! Java接口多线程并发测试 一,首先写一个接口post 请求代码: import org.apach ...
- SSH无密码登录:只需两个简单步骤 (Linux)
最后更新 2017年4月8日 分类 最新文章 服务器安全 标签 RSA SSH Key 非对称加密 如果你管理一台Linux服务器,那么你就会知道每次SSH登录时或者使用scp复制文件时都要输入密码是 ...
- 将Pytorch模型从CPU转换成GPU
1. 如何进行迁移 对模型和相应的数据进行.cuda()处理.通过这种方式,我们就可以将内存中的数据复制到GPU的显存中去.从而可以通过GPU来进行运算了. 1.1 判定使用GPU 下载了对应的GPU ...
- Java设计模式应用——工厂模式
工厂模式有三种:简单工厂.工厂方法.抽象工厂 一. 抽象工厂 1. 一个可以生产多种产品的工厂: 2. 不改变工厂无法生产新的产品. package com.coshaho.learn.factory ...
- DOS操作系统的历史
昨日(7月27日),微软公司的DOS操作系统迎来了30岁生日. DOS是历史上一个划时代的产品,标识着PC(个人电脑)的崛起和普及,对计算机行业影响深远. 只有了解DOS的历史,才能理解今天的计算机工 ...
- zookeeper与卡夫卡集群搭建
首先这片博客没有任何理论性的东西,只是详细说明kafka与zookeeper集群的搭建过程,需要三台linux服务器. java环境变量设置 zookeeper集群搭建 kafka集群搭建 java环 ...
- ArcThemALL!5.1:解压、脱壳、压缩样样精通
原文链接:http://www.ithome.com/html/soft/57033.htm ArcThemALL!软件主要功能: 1.支持压缩和解压功能,支持常用的7z.zip.cab.iso.ra ...
- android 实践项目 总结 (修改)
Android手机定位与地图实现 在一个不熟悉的环境中,获得自己的位置,选择合适的就餐地点,住宿和公交路线成为一项难题.本次的实践项目就是为了解决上述难题的,通过调用百度地图的接口实现定位.查询公交路 ...
- Eclipse给方法或者类添加自动注释
自动生成注释: 在团队开发中,注释是必不可少的,为了是自己的注释看起来更加优雅,注释的格式应该统一,我们可以使用Eclipse注释模板自动生成注释. 具体操作如下: 打开注释模板编辑窗口:Window ...