我在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;
};
我现在已将它注释掉了,但我确定它显而易见的是我迷茫的地方以及我搞砸了。如果有人能提供任何帮助,我们将不胜感激。
答案 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;
};
应该编译,如果你想要的话。