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

 

posted @ 2017-01-03 15:39  CppSkill  阅读(329)  评论(0编辑  收藏  举报