我正在尝试向我的项目添加一个简单的消息传递系统,其中事件可以由函数调用,这将导致注册到该事件的所有回调被调用。
现在,执行此操作的逻辑方法是使用函数指针。可以很容易地将指针传递给事件管理器所需的回调函数,以进行注册。事件回调函数总是返回int
并以void*
为参数。
但是我不想将静态全局函数注册为我的事件回调 - 我想用类成员函数来完成。
是否可以使用C ++完成此操作?存储和调用指向不同类的成员函数的指针,但使用相同的函数标题。
如果无法做到这一点,您对我如何解决这个问题有什么建议吗?我真的想直接将事件监听器添加到我的类中。
答案 0 :(得分:7)
是的,这是可能的。 C++0x has the function
class that handles this,正如其他人所指出的那样,Boost也有类似的设施。
你也可以自己动手,但语法不适合胆小的人:
#include <iostream>
class Callable
{
public:
virtual ~Callable() {}
virtual int operator() (void* args) = 0;
};
class CallableFreeFunction : public Callable
{
public:
CallableFreeFunction(int (*func)(void*)) : func_(func) {}
virtual int operator() (void* args) { return (*func_)(args); }
private:
int (*func_)(void*);
};
template <typename tClass>
class ClassMemberCallable : public Callable
{
public:
ClassMemberCallable(tClass* instance, int (tClass::*memberfunction)(void*)) : instance_(instance), memberfunc_(memberfunction) {}
virtual int operator() (void* args) { return (instance_->*memberfunc_)(args); }
private:
tClass* instance_;
int (tClass::*memberfunc_)(void*);
};
class Foo
{
public:
int derp(void* args)
{
std::cout << args << '\n';
return 2;
}
};
int freefunctionfoo(void* args)
{
std::cout << "free" << args << '\n';
return 2;
}
int main(int argc, char* argv[])
{
Foo myfoo;
Callable* callable = new ClassMemberCallable<Foo>(&myfoo, &Foo::derp);
(*callable)(0);
delete callable;
callable = new CallableFreeFunction(freefunctionfoo);
(*callable)(0);
delete callable;
std::cin.get();
return 0;
}
这展示了一种以不透明的方式处理自由函数和成员函数的方法。这是一个简单的例子,可以通过多种方式使其更通用和更健壮。我会向您推荐这些页面以获取语法帮助:
http://www.newty.de/fpt/index.html
http://www.parashift.com/c++-faq-lite/pointers-to-members.html
我还建议您查看更多想法:
答案 1 :(得分:3)
当然有可能!请查看Boost.Signal2和Boost.Bind。
Boost.Signal2基本上实现了信号和插槽系统,这正是您所需要的。
然后,您可以使用boost::bind
这是std::bind1st
和std::bind2nd
的一般化来获取函数对象包装器,基本上是您能想到的任何东西(在您的情况下,成员方法)。它真的很强大。
请参阅此官方boost tutorial。
答案 2 :(得分:2)
这是我做这样的工作的不那么好的尝试: 首先,您需要一个基本事件处理程序类,现在让我们称之为EvtHandler:
class Event; //implement this yourself, it shall contain general but good info about event
class EvtHandler
{
public:
virtual void handleEvent (Event & evt);
};
然后,每个应该以某种方式处理事件的类应该派生自这个类,并且只要它们返回相同的数据类型,它们就可以 实现新功能。 void 在这种情况下)并收到相同的参数(在这种情况下事件)。像这样:
class Foo : public EvtHandler
{
public:
void handleFooEvent (Event & event);
};
然后我为每个特殊事件实现了消息中心,必须在需要时注册监听器和派遣事件:
class ShutdownMessageCenter
{
typedef std::map<EventHandler *, event_func> ListenerMap;
public:
void register (EvtHandler * handler, void(EvtHandler::*memFunc)(Event &)) {
m_lmap[handler] = memFunc;
}
void callListeners () {
Event shutdown_event (EM_SHUTDOWN /*just imagine this can mean something, idk*/);
ListenerMap::iterator itr = m_lmap.begin ();
for (; itr != m_lmap.end(); ++itr) {
EvtHandler * handler = itr->first;
void (EvtHandler::*func)(Event &) = itr->second;
(handler->*func)(shutdown_event);
}
}
private:
ListenerMap m_lmap;
};
然后,您可以将EvtHandlers注册到此特定消息中心,例如!
ShutdownMessageCenter message_center;
EvtHandler * some_handler = new EvtHandler ();
Foo * some_foo = new Foo ();
message_center.register (some_handler, &EvtHandler::handleEvent);
message_center.register (some_foo, static_cast<void (EvtHandler::*)(Event &)>(&Foo::handleFooEvent);
message_center.callListeners ();
但是再一次这根本不好,只是想我会分享!抱歉这个烂摊子,哈哈!
答案 3 :(得分:1)
我不完全确定您要存档的内容,但也许您应该查看Boost Signals2
如果你想创建某种信号/插槽机制,那将非常有用。
答案 4 :(得分:0)
不,这是不可能的(除非您使用.net执行c ++ / cli)。
现在,您仍然可以创建静态函数,将对象作为参数传递给他们,他们唯一要做的就是在该对象上调用您的成员函数。 (实际上首先需要演员表。)
答案 5 :(得分:0)
我管理的最接近的是注册静态成员函数作为回调。除了事件处理程序发送的参数之外,静态成员还将object(this)指针作为参数,并使用它来调用成员函数。
class myClass{
public:
static void callback(void *arg, void *obj)
{
if (obj)
reinterpret_cast<myClass*>(obj)->cb(arg);
}
private:
void cb(void *arg);
};
使用您的处理程序注册myClass::callback
和this
。如果您在可以返回的内容中受到限制,则可能需要将此包装在arg引用的结构中。
答案 6 :(得分:0)
我在SWIG中使用lukes答案,因为SWIG不支持所有C ++ 11功能...使用Parsa Jamshidis方法甚至可以进一步改善这一点。
我对其进行了修改,以涵盖更多情况(可变数量的参数和可变的返回类型):
contents.beginText();