C++中的简单事件系统
Simple event system in C++
我正在为我的游戏引擎设计一个简单的事件系统。
我想实现以下事件调度程序接口:
// Create event dispatcher.
Dispatcher dispatcher;
// Create objects b and c.
// Created objects extend base A class.
A* b = new B();
A* c = new C();
// Register b and c in dispatcher.
// I guess I should also pass member function pointer,
// but I am not sure how to do it.
// Like this; dispatcher.Add(b, &B::DoWork) ?
// Member function that I want to accept is always bool func(/*no params*/)
dispatcher.Add(b /*, member function pointer?*/);
dispatcher.Add(c /*, member function pointer?*/);
// Trigger passed functions for registered objects.
dispatcher.Trigger();
我想,我需要在 Dispatcher 中使用某种包装器结构来保存 [pObject, pFunc] 对。
struct Wrapper
{
A* pObj; // Of base class A.
// ?? // Pointer to given member function of A.
};
我不知道如何实现成员函数指针逻辑。
因为我需要一个实时系统,所以我更喜欢一个相对快速的解决方案。我感谢所有建议。
我宁愿避免使用第 3 方库。
如果您可以适当地构造您的 A 派生 类 以便您可以拥有 process()
方法,您可以简单地使用多态分派。
类似于:
struct A
{
virtual void process() = 0;
virtual ~A() {}
}
struct B : public A
{
virtual void process() { /* process event B... */ }
}
struct C : public A
{
virtual void process() { /* process event C... */ }
}
您的调度程序的触发方法将只为所有已注册的对象调用指针上的 process()
方法并让多态性调用适当的方法。
根据评论,您可以使用 std::function
或类似于提议的结构 here。
它遵循第二个建议的最小和工作示例:
class Dispatcher {
Dispatcher() { }
template<class C, void(C::*M)() = C::receive>
static void invoke(void *instance) {
(static_cast<C*>(instance)->*M)();
}
public:
template<class C, void(C::*M)() = &C::receive>
static Dispatcher create(C *instance) {
Dispatcher d;
d.fn = &invoke<C, M>;
d.instance = instance;
return d;
}
void operator()() {
(fn)(instance);
}
private:
using Fn = void(*)(void *);
Fn fn;
void *instance;
};
struct S {
void receive() { }
};
int main() {
S s;
Dispatcher d = Dispatcher::create(&s);
d();
};
请注意,它必须根据您的要求进行相应修改(目前,目标成员方法没有 return 值并且不接受参数)。
此外,它可以很容易地扩展为存储目标成员方法的数组,这就是您正在寻找的:只需存储一对 instance
s 和 invoke
函数的向量。
此外,您可以使用带有 Dispatcher
功能的可变参数模板,使其更加灵活。这样,您将能够定义具有不同 return 类型和参数列表的 Dispatcher
。
编辑
它遵循接受多个目标成员函数的 Dispatcher
示例。
通过上面提到的可变参数模板扩展它仍然很容易。
#include <vector>
#include <utility>
class Dispatcher {
template<class C, void(C::*M)() = C::receive>
static void invoke(void *instance) {
(static_cast<C*>(instance)->*M)();
}
public:
template<class C, void(C::*M)() = &C::receive>
void bind(C *instance) {
auto pair = std::make_pair(&invoke<C, M>, instance);
targets.push_back(pair);
}
void operator()() {
for(auto pair: targets) {
(pair.first)(pair.second);
}
}
private:
using Fn = void(*)(void *);
std::vector<std::pair<Fn, void*>> targets;
};
struct S {
void receive() { }
};
struct T {
void receive() { }
};
int main() {
S s;
T t;
Dispatcher d;
d.bind(&s);
d.bind(&t);
d();
};
请注意,在上面的示例中,不能保证提交为 instance
的指针在实际使用后仍然有效。您应该注意绑定对象的生命周期,或者稍微修改示例以引入更安全的句柄。
我正在为我的游戏引擎设计一个简单的事件系统。 我想实现以下事件调度程序接口:
// Create event dispatcher.
Dispatcher dispatcher;
// Create objects b and c.
// Created objects extend base A class.
A* b = new B();
A* c = new C();
// Register b and c in dispatcher.
// I guess I should also pass member function pointer,
// but I am not sure how to do it.
// Like this; dispatcher.Add(b, &B::DoWork) ?
// Member function that I want to accept is always bool func(/*no params*/)
dispatcher.Add(b /*, member function pointer?*/);
dispatcher.Add(c /*, member function pointer?*/);
// Trigger passed functions for registered objects.
dispatcher.Trigger();
我想,我需要在 Dispatcher 中使用某种包装器结构来保存 [pObject, pFunc] 对。
struct Wrapper
{
A* pObj; // Of base class A.
// ?? // Pointer to given member function of A.
};
我不知道如何实现成员函数指针逻辑。 因为我需要一个实时系统,所以我更喜欢一个相对快速的解决方案。我感谢所有建议。
我宁愿避免使用第 3 方库。
如果您可以适当地构造您的 A 派生 类 以便您可以拥有 process()
方法,您可以简单地使用多态分派。
类似于:
struct A
{
virtual void process() = 0;
virtual ~A() {}
}
struct B : public A
{
virtual void process() { /* process event B... */ }
}
struct C : public A
{
virtual void process() { /* process event C... */ }
}
您的调度程序的触发方法将只为所有已注册的对象调用指针上的 process()
方法并让多态性调用适当的方法。
根据评论,您可以使用 std::function
或类似于提议的结构 here。
它遵循第二个建议的最小和工作示例:
class Dispatcher {
Dispatcher() { }
template<class C, void(C::*M)() = C::receive>
static void invoke(void *instance) {
(static_cast<C*>(instance)->*M)();
}
public:
template<class C, void(C::*M)() = &C::receive>
static Dispatcher create(C *instance) {
Dispatcher d;
d.fn = &invoke<C, M>;
d.instance = instance;
return d;
}
void operator()() {
(fn)(instance);
}
private:
using Fn = void(*)(void *);
Fn fn;
void *instance;
};
struct S {
void receive() { }
};
int main() {
S s;
Dispatcher d = Dispatcher::create(&s);
d();
};
请注意,它必须根据您的要求进行相应修改(目前,目标成员方法没有 return 值并且不接受参数)。
此外,它可以很容易地扩展为存储目标成员方法的数组,这就是您正在寻找的:只需存储一对 instance
s 和 invoke
函数的向量。
此外,您可以使用带有 Dispatcher
功能的可变参数模板,使其更加灵活。这样,您将能够定义具有不同 return 类型和参数列表的 Dispatcher
。
编辑
它遵循接受多个目标成员函数的 Dispatcher
示例。
通过上面提到的可变参数模板扩展它仍然很容易。
#include <vector>
#include <utility>
class Dispatcher {
template<class C, void(C::*M)() = C::receive>
static void invoke(void *instance) {
(static_cast<C*>(instance)->*M)();
}
public:
template<class C, void(C::*M)() = &C::receive>
void bind(C *instance) {
auto pair = std::make_pair(&invoke<C, M>, instance);
targets.push_back(pair);
}
void operator()() {
for(auto pair: targets) {
(pair.first)(pair.second);
}
}
private:
using Fn = void(*)(void *);
std::vector<std::pair<Fn, void*>> targets;
};
struct S {
void receive() { }
};
struct T {
void receive() { }
};
int main() {
S s;
T t;
Dispatcher d;
d.bind(&s);
d.bind(&t);
d();
};
请注意,在上面的示例中,不能保证提交为 instance
的指针在实际使用后仍然有效。您应该注意绑定对象的生命周期,或者稍微修改示例以引入更安全的句柄。