1

我在 newty.de 上关注 Lars Haendel 的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

4 回答 4

4

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

结构 TBaseCallback
    void operator()(IGameEvent *pEvent) { _Call(pEvent); };
    void Exec(IGameEvent *pEvent) { _Call(PEvent); }
私人的:
    虚空 _Call(IGameEvent *pEvent)=0;
};

结构事件挂钩
{
    字符*名称;
    EventHookMode 模式;
    TBaseCallback *p;
    无效调度(char *msg; IGameEvent *e) const {
      if(strcmp(msg,name)==0) p->Exec(e);
   }
};

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

顺便说一句:当您将其推向更复杂的抽象时,您很快就会发现为什么面向对象是一个破碎的概念。使用 DLL 加载的派生类,您根本无法使用 dynamic_cast 开关作弊(因为它们是封闭的/特定的/有限的/确定的)。

于 2010-11-26T04:48:58.140 回答
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()它们时,将调用正确的类版本。

于 2010-11-26T04:29:20.523 回答
0

我看到的问题(很可能还有其他问题)是在pEventCallback's 类型中,模板参数应该是类类型,但实际上是指针类型。一种解决方法(不限制回调包装的类型)是使用基本类型:

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

如果TEventCallback's 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您不妨将call设为默认实现TBaseCallback::operator()

void TBaseCallback::Call(IGameEvent *pEvent) { this->operator()(pEvent); };
于 2010-11-26T04:34:01.133 回答
0

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

试试这个:

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

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

于 2010-11-26T10:12:26.970 回答