C ++方法指针?

时间:2015-05-26 00:10:51

标签: c++ visual-studio assembly

我在Wintel上运行,只要我知道方法签名,我希望能够调用任何对象的变量方法。以下汇编程序是否正确?我需要保存/恢复ECX吗?它似乎工作,但我想知道我是否遗漏了一些东西。是的,是的,告别类型安全,危险是我的中间名......

那么,我为什么要这样做呢?我有一个消息分发系统。业务逻辑订阅消息,分发系统在它们进入时将它们移出。现在我正在使用接口定义。我有业务对象需要接收多种消息类型。每个处理函数都有一个if-else语句块来确定消息类型。我希望单个类订阅多个消息类型,并为每种类型使用不同的方法。我可以切换到函数指针,但后来我有一堆静态方法和非静态计数器部分。

它只有3个汇编指令,它有多糟糕? 俯视滑坡

#include <stdio.h>

class A {
public:
    A(int i){
        m_i = i;
    }

    void test(int i){
        printf("m_i = %i, i = %i\n",m_i,i);
    }

private:
    int m_i;
};

void callmethod(void *object, const void *function, int i){
    __asm {
        push [i];
        mov ecx, object;
        call function;
    }
}

int main(){
    A a(123);
    callmethod(&a,_ADDRESSOF(A::test),456);
    return 0;
}

输出:

  

m_i = 123,i = 456

以下是我现在所拥有的更详细的例子以及解释我想要做的事情的评论。

#include <stdio.h>
#include <unordered_map>
#include <list>

using std::unordered_map;
using std::list;

class IMessage {
};

class MessageHandler {
public:
    virtual ~MessageHandler(){}
    virtual void HandleMessage(int type, IMessage *message) = 0;
};

class MessageDispatcher {
public:

    void Subscribe(int type, MessageHandler *callback){
        m_callbacks[type].push_back(callback);
    }

    void ProcessMessage(int type, IMessage *message){
        if (m_callbacks.find(type) != m_callbacks.end()){
            list<MessageHandler*> &callbacks = m_callbacks[type];
            for (list<MessageHandler*>::iterator i = callbacks.begin(); i != callbacks.end(); ++i){
                (*i)->HandleMessage(type,message);
            }
        }
    }

private:

    unordered_map<int,list<MessageHandler*> > m_callbacks;

};

class BusinesLogic : public MessageHandler {
public:

    BusinesLogic(MessageDispatcher *md){
        md->Subscribe(0,this); // I want to put HandleType0 here like this
                               // md-Subscribe(0,this,HandleType0);
        md->Subscribe(1,this); // I want to put HandleType1 here like this
                               // md-Subscribe(1,this,HandleType1);
    }

private:

    void HandleType0(IMessage *message){
        printf("Got type 0\n");
    }

    void HandleType1(IMessage *message){
        printf("Got type 1\n");
    }

    virtual void HandleMessage(int type, IMessage *message){
        // I want to do away with this switch block and let the MessageDispatcher
        // class call into the HandleType0 and HandleType1 methods directly
        // without using static methods
        switch (type){
        case 0:
            HandleType0(message);
            break;
        case 1:
            HandleType1(message);
            break;
        }
    }
};

int main(){

    MessageDispatcher md;

    BusinesLogic bl(&md);

    md.ProcessMessage(0,nullptr);
    md.ProcessMessage(1,nullptr);

    return 0;

}

1 个答案:

答案 0 :(得分:0)

你想在他的第一条评论中使用凯建议成员的指针。

这样做的简单方法类似于以下示例:

virtual void HandleMessage(int type, IMessage *message){
    typedef void (BusinesLogic::*handler_mfn_type)(IMessage *);
    static const handler_mfn_type dispatch_table[] = {
        &BusinesLogic::HandleType0,
        &BusinesLogic::HandleType1
    };
    handler_mfn_type mfn = dispatch_table[type];
    (this->*mfn)(message);
}

没有内联汇编程序,也没有静态函数。也没有订阅方法本身,但我不确定这是不是坏事。

如果您真的希望能够在Subscribe调用中传递该方法,那么您需要将它包装在一个类中,该类将(指针)方法与指向该对象的指针捆绑在一起。无法避免需要两者都调用方法的事实。

创建一个基类和这样的模板:

class callback_base {
public:
    virtual void call_handler(IMessage *) = 0;
};

template <class T>
class callback: public callback_base {
    typedef void (T::*mfn_type)(IMessage *);

    T *obj;
    mfn_type mfn;

public:
    callback(T *a, mfn_type b): obj(a), mfn(b) {}

    virtual void call_handler(IMessage *msg) {
        (obj->*mfn)(msg);
    }
};

并像这样使用它:

md->Subscribe(0,new callback<BusinesLogic>(this, &BusinesLogic::HandleType0));
md->Subscribe(1,new callback<BusinesLogic>(this, &BusinesLogic::HandleType1));
void Subscribe(int type, callback_base *cb){
    m_callbacks[type].push_back(cb);
}
void ProcessMessage(int type, IMessage *message){
    ...
        for (list<callback_base *>::iterator i = callbacks.begin(); i != callbacks.end(); ++i){
            (**i).call_handler(message);
        }