• 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
    ", p01);
        printf("p02 : %08X
    ", p02);
        printf("p03 : %08X
    ", p03);
    
        CA a;
        a.i = 10;
        printf("&a : %08X
    ", &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
    ", iRtn, iRtn);
    
        // *** *** ***
        
        CRtn cr;
        printf("&cr : %08X, %d
    ", &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
    ", &cr, &cr);
    
        cr = a.ReturnObj02(3, 9);
        //#pragma OPTIMIZE ON
        printf("&cr : %08X, %d
    ", &cr, &cr);
    
        
        Tcfp_CR_IF cfp01;
        cfp01.Set(&a, p03);
        CRtn cr01;
        printf("&cr01 : %08X, %d
    ", &cr01, &cr01);
        printf("&cfp01 : %08X, %d
    ", &cfp01, &cfp01);
        cr01 = cfp01.Call(3, 9);
        printf("cr01.Fi : %08X, %d
    ", 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

  • 相关阅读:
    对easyui-validatebox的验证类型的扩展,值必须在某个区间
    从零开始学springboot笔记(六)-Spring boot之Spring Boot Spring Data JPA介绍
    从零开始学springboot笔记(五)-Spring boot之Spring Data- JPA 笔记
    从零开始学springboot笔记(四)-Spring boot之热部署之Springbootdevtools(工作中使用)
    JQuery给指定的表格的输入框或其他组件赋值
    oracle开发技巧
    数据库开发要求
    user_tab_columns和user_tab_cols的区别
    windows xp显示文件的后缀
    vue学习遇到的问题
  • 原文地址:https://www.cnblogs.com/cppskill/p/6245117.html
Copyright © 2020-2023  润新知