C++事件系统设计
问题描述:
我需要在C++中使用事件系统。我主要有四个要求:C++事件系统设计
- 速度
- 易于使用
- 类型安全
- 友好破坏
通过“友好破坏”我的意思是事件和用户需要管理当其中一个被破坏时,它们断开连接:
- 事件不应调用已销毁的订户。
- 用户应该无法从已销毁的事件中注销。
我不知道是否有人会比我想出了一个更好的设计:
用户观点:
struct ClickEventArg {};
//-------------------------------------------------------------------------
class Button
{
public:
Event<ClickEventArg&> Clicked;
void SendClick(ClickEventArg& arg)
{
Clicked(this, arg);
}
};
//-------------------------------------------------------------------------
class User
{
public:
void Register(Button* button)
{
button->Clicked.Subscribe(m_suscriber, this, &User::OnButtonClicked);
}
void OnButtonClicked(void* sender, ClickEventArg& arg)
{
std::cout << "button clicked";
}
private:
EventSubscriber m_suscriber;
};
//-------------------------------------------------------------------------
void Test()
{
Button* button = new Button();
User* user = new User();
user->Register(button);
button->SendClick(ClickEventArg());
delete user;
button->SendClick(ClickEventArg());
}
内部代码:
class EventSubscriber;
//-------------------------------------------------------------------------
class BaseEvent
{
public:
virtual void UnSubscribe(EventSubscriber& subscriber) = 0;
};
//-------------------------------------------------------------------------
template <class TEventArgs>
class Event : public BaseEvent
{
public:
~Event()
{
UnSubscribeAll();
}
typedef fastdelegate::FastDelegate2<void*, TEventArgs> EventHandler;
inline void operator() (void* sender, TEventArgs args) const
{
for (SubscriberMap::const_iterator it = m_subscribers.begin(); it != m_subscribers.end(); ++it)
it->second(sender, args);
}
template <class TClass, class TEventArgs>
void Subscribe(EventSubscriber& subscriber, TClass* object, void (TClass::*methodAddress)(void* sender, TEventArgs e))
{
subscriber.Subscribe(this);
m_subscribers[&subscriber] = fastdelegate::MakeDelegate(object, methodAddress);
}
void UnSubscribe(EventSubscriber& subscriber)
{
subscriber.UnSubscribe(this);
m_subscribers.erase(&subscriber);
}
void UnSubscribeAll()
{
for (SubscriberMap::const_iterator it = m_subscribers.begin(); it != m_subscribers.end(); ++it)
it->first->UnSubscribe(this);
m_subscribers.clear();
}
private:
typedef std::map<EventSubscriber*, EventHandler> SubscriberMap;
SubscriberMap m_subscribers;
};
//-------------------------------------------------------------------------
class EventSubscriber
{
template <class TEventArgs> friend class Event;
public:
~EventSubscriber()
{
UnSubscribeAll();
}
private:
void Subscribe(BaseEvent* e)
{
m_subscriptions.insert(e);
}
void UnSubscribe(BaseEvent* e)
{
m_subscriptions.erase(e);
}
void UnSubscribeAll()
{
EventSet copy(m_subscriptions);
for (EventSet::iterator it = copy.begin(); it != copy.end(); ++it)
{
(*it)->UnSubscribe(*this);
}
}
typedef std::set<BaseEvent*> EventSet;
EventSet m_subscriptions;
};
您可能请注意,我使用了本文中的快速代表http://www.codeproject.com/KB/cpp/FastDelegate.aspx。
“Friendly Destruction”方面需要EventSubscriber类。 (否则我会用一个更漂亮的设计,如在C#中)
欢迎任何反馈。
谢谢。
答
如果你添加智能指针到这个事件系统,你应该保持良好状态。这个例子非常类似于C#事件系统,没有很多可以在可下载代码之上轻松实现的保护措施。 http://www.theorangeday.com/tutorials/c-event-system-using-delegates/
为什么不使用可用的库,如Boost Signals(http://www.boost.org/doc/libs/1_44_0/doc/html/signals.html)? – 2010-11-09 05:24:31
我建议在BaseEvent中添加一个虚拟(或受保护的)析构函数 – icecrime 2010-11-09 08:17:22
我无法使用boost,但我会检查它们是如何实现的。 Thx icecrime,有趣的你回答了我:) – noon 2010-11-09 17:10:34