C ++ Functor回调设置

时间:2010-11-26 03:46:56

标签: c++ callback handler functor

我在newty.de上关注Lars Haendel的Functor tutorial来设置回调系统。我有点困惑,我希望有人可以帮助我。

这是我的Functor模板

#include <igameevents.h>

// Abstract Base Class (Functor)
class TBaseCallback
{
public:

    // two possible functions to call member function. virtual cause derived
    // classes will use a pointer to an object and a pointer to a member function
    // to make the function call
    virtual void operator()(IGameEvent *pEvent){};  // call using operator
    virtual void Call(IGameEvent *pEvent) {};       // call using function
};


// Derived Template Class
template <class TClass> class TEventCallback : public TBaseCallback
{
private:

    void (TClass::*funcPtr)(IGameEvent*);       // pointer to member function
    TClass* thisPtr;                            // pointer to object

public:

    // constructor - takes pointer to an object and pointer to a member and stores them in two private variables
    TEventCallback(TClass* _thisPtr, void(TClass::*_funcPtr)(const char*))
    { thisPtr = _thisPtr;  funcPtr=_funcPtr; };

    // override operator "()"
    virtual void operator()(IGameEvent *pEvent)
    { (*thisPtr.*funcPtr)(pEvent); };           // execute member function

    // override function "Call"
    virtual void Call(IGameEvent *pEvent)
    { (*thisPtr.*funcPtr)(pEvent); };           // execute member function
};

我想要做的是基本上允许其他.dll使用我的HookGameEvent()函数,并且当调用游戏事件时,我可以运行我的钩子的向量||列表,检查事件名称是否匹配,然后根据需要执行回调。令我困惑的是,我如何将回调存储在我的HookEvent结构中,看起来像这样。

std::vector<EventHook*> m_EventHooks;

struct EventHook
{
    char *name;
    EventHookMode mode;
    //TEventCallback<IGameEvent*> pEventCallback;
};

我现在已将它注释掉了,但我确定它显而易见的是我迷茫的地方以及我搞砸了。如果有人能提供任何帮助,我们将不胜感激。

4 个答案:

答案 0 :(得分:3)

大多数人不了解继承。通常,派生类是实现细节。你唯一一次说出他们的名字就是建造它们。此外,基类中的虚函数应该是私有的和纯的,并且在派生类中应该是完全不可访问的,这是C ++中的一个设计错误,它不会被强制执行。

struct TBaseCallback
    void operator()(IGameEvent *pEvent) { _Call(pEvent); }; 
    void Exec(IGameEvent *pEvent) { _Call(PEvent); }
private:
    virtual void _Call(IGameEvent *pEvent)=0;
};

struct EventHook
{
    char *name;
    EventHookMode mode;
    TBaseCallback *p;
    void dispatch(char *msg; IGameEvent *e) const { 
      if(strcmp(msg,name)==0) p->Exec(e); 
   }
};

通过这种设计,从TBaseCallback派生的类中没有任何区别,也不应该如此。只有抽象应该是公开可见的。在普通代码中,这很难强制执行..当你使用DLL来获取派生类时,它绝对是强制性的,因为派生类的集合是开放/任意/无限/不确定的(请你选择)。

BTW:当您将其推向更复杂的抽象时,您很快就会发现为什么面向对象是一个破碎的概念。使用DLL加载的派生类,你只需不能欺骗dynamic_cast开关(因为它们是关闭的/特定的/有限的/确定的)。

答案 1 :(得分:0)

要进行回调的类应该包含要调用的Functor对象列表。这些将是你的

std::vector<EventHook*> m_EventHooks;

现在,EventHook应该有一个虚函数:

struct EventHook
{
    ...
    virtual void notifyMe();
}

然后,每个有兴趣获得通知的人都会创建自己的钩子实现:

struct MyEventHook : public EventHook
{
    virtual void notifyMe() { ... whatever I want to do in that case ... }
}

通过多态的奇迹,当你迭代m_EventHooks容器的所有元素并为那些调用notifyMe()时,将调用正确的类版本。

答案 2 :(得分:0)

我看到的问题(很可能是其他问题)是在pEventCallback的类型中,模板参数应该是类类型,但实际上是指针类型。一个修复(不限制回调包装的类型)是使用基类型:

struct EventHook
{
    char *name;
    EventHookMode mode;
    TBaseCallback* pCallback;
};

如果TEventCallback的API更多,并且需要通过EventHook访问,则应将TEventCallback中处理对象及其方法的代码移至一个单独的子类。

// Example EventCallback that takes other args
class EventCallback : public TBaseCallback {
public:
    EventCallback();
    EventCallback(const EventArgs& evtArgs);
    // EventCallback specific methods ...
    virtual EventArgs& args();
    virtual const EventArgs& args() const;
}

/* TReturn allows for calling methods with a non-void return. Return value is ignored. 
 */
template <class TClass, typename TReturn = void> 
class TMethodCallback : public EventCallback
{
private:
    typedef TReturn (TClass::*TMeth)(IGameEvent*);
    TMeth funcPtr;       // pointer to member function
    TClass* thisPtr;                            // pointer to object

public:

    // constructor - takes pointer to an object and pointer to a member and stores them in two private variables
    TMethodCallback(TClass* _thisPtr, TMeth _funcPtr)
    { thisPtr = _thisPtr;  funcPtr=_funcPtr; };

    // override operator "()"
    virtual void operator()(IGameEvent *pEvent)
    { (*thisPtr.*funcPtr)(pEvent); };           // execute member function

    // override function "Call"
    virtual void Call(IGameEvent *pEvent)
    { (*thisPtr.*funcPtr)(pEvent); };           // execute member function
};

题外话

您也可以默认实施TBaseCallback::Call来电TBaseCallback::operator()

void TBaseCallback::Call(IGameEvent *pEvent) { this->operator()(pEvent); };

答案 3 :(得分:0)

我认为您将遇到复杂的编译器错误,因为您在模板实例化中使用T *而不是T.

试试这个:

struct EventHook
{
    char *name;
    EventHookMode mode;
    TEventCallback<IGameEvent> pEventCallback;
}; 

应该编译,如果你想要的话。