非静态类成员函数指针解决方案

5 11 月, 2009 by admin Leave a reply »

众所周知,我们无法定义一个指向类的非静态成员函数。在Borland C/C++中,Bolrand公司添加了关键字__closure用来定义这种特殊的指针。在Visual C/C++中虽然也有解决方染,但是使用麻烦,且不易于使用。网络上下存在很多解决方案,但作者均未看到较为好用的解决方案。

本文即提供一种于x86-32平台下的解决方案,使用方式类似于Borland C/C++,十分方便。代码在Borland C/C++ 5.82Microsoft C/C++ 14.0 (Visual C/C++ 8.0)下测试通过。


#include<stdio.h>
#include<stddef.h>

class _Object{};

#if defined(SetEventCall)||defined(CallEvent)||defined(DefineEvent)
    #error SetEventCall,CallEvent,DefineEvent 已经定义
#endif//

#ifdef __BORLANDC__

    #define SetEventCall(event_obj,event_func)              event_obj=event_func
    #define CallEvent(event_obj)                            event_obj
    #define DefineEvent(name,result,intro)                  result (__closure *name)intro

#else

    #pragma warning(disable:4311)

    template <typename T> struct EventFunc
    {
        unsigned __int32 this_address;
        unsigned __int32 func_address;

        _Object *This;
        T Func;

        EventFunc()
        {   
            this_address=offsetof(EventFunc,This);
            this_address+=(unsigned __int32)this;

            func_address=offsetof(EventFunc,Func);
            func_address+=(unsigned __int32)this;
        }
    };

    #define SetEventCall(event_obj,event_func)      {   \
                                                        unsigned __int32 this_address=event_obj.this_address;   \
                                                        unsigned __int32 func_address=event_obj.func_address;   \
                                                        \
                                                        {   \
                                                            __asm mov eax,this_address  \
                                                            __asm mov ebx,this  \
                                                            __asm mov [eax],ebx \
\
                                                            __asm mov eax,func_address  \
                                                            __asm mov ebx,event_func    \
                                                            __asm mov [eax],ebx \
                                                        }   \
                                                    }

    #define CallEvent(event_obj)                    (event_obj.This->*(event_obj.Func))             //(*(event_obj.This).*(event_obj.Func))

    #define DefineEvent(name,result,intro)          EventFunc<result (_Object:: *)intro> name;
#endif//__BORLANDC__

class Button
{
public:

    DefineEvent(OnClick,void,(Button *,int));     //定义事件,原型为: void OnClick(Button *,int)

public:

    Button()
    {
        printf("Button this=%p\n",this);
    }

    void TestButtonClick()
    {
        CallEvent(OnClick)(this,0);               //呼叫OnClick,原型为: OnClick(this,0)
    }
};

class Test
{
    Button *button;

public:

    void OnButtonClick(Button *but,int)
    {
        printf("Test::OnButtonClick,this=%p,but=%p\n",this,but);
    };

public:

    Test()
    {
        printf("Test this=%p\n",this);

        button=new Button;

        SetEventCall(button->OnClick,OnButtonClick);              //设定button->OnClick事件的处理函数为OnButtonClick

        button->TestButtonClick();
    }
};

void main(int,char **)
{
    Test *test;

#ifdef __BORLANDC__
    printf("Compiler: Borland C/C++ or Turbo C/C++ %d.%d%d\n",(__BORLANDC__>>8),((__BORLANDC__&0xF0)>>4),(__BORLANDC__&0x0F));
#endif
#ifdef _MSC_VER
    printf("Compiler: Microsoft C/C++ %.2f (Visual C/C++ %.2f)\n",_MSC_VER/100.f,_MSC_VER/100.f-6);
#endif//

    printf("Compile Time: %s %s\n\n",__DATE__,__TIME__);

    test=new Test;

    delete test;
}

Compiler: Borland C/C++ or Turbo C/C++ 5.82
Compile Time: Dec 23 2006 17:34:48

Test this=00902D50
Button this=00902D64
Test::OnButtonClick,this=00902D50,but=00902D64

Compiler: Microsoft C/C++ 14.00 (Visual C/C++ 8.00)
Compile Time: Dec 23 2006 17:34:00

Test this=003826D0
Button this=00382700
Test::OnButtonClick,this=003826D0,but=00382700
Advertisement

发表回复

You must be logged in to post a comment.
鄂ICP备09027626号