【问题标题】:C++ event system design [closed]C ++事件系统设计[关闭]
【发布时间】:2010-11-09 05:18:49
【问题描述】:

我需要在 C++ 中使用事件系统。我主要有四个要求:

  1. 速度
  2. 易于使用
  3. 类型安全
  4. 友好破坏

我所说的“友好破坏”是指事件和订阅者在其中一个被破坏时需要管理他们的断开连接:

  • 事件不应调用已销毁的订阅者。
  • 订阅者不应该能够从已销毁的事件中取消注册。

我想知道是否有人会有比我想出的更好的设计:

用户观点:

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

“友好破坏”方面需要 EventSubscriber 类。 (否则我会使用像 C# 这样更漂亮的设计)

欢迎任何反馈。

谢谢。

【问题讨论】:

  • 为什么不直接使用可用的库,例如 Boost Signals (boost.org/doc/libs/1_44_0/doc/html/signals.html)?
  • 我建议向 BaseEvent 添加一个虚拟(或受保护)析构函数
  • 我不能使用 boost,但我会检查他们是如何实现它的。谢谢icecrime,有趣的是你回复了我:)

标签: c++ events delegates


【解决方案1】:

如果您想要线程安全,请使用 boost::signalsboost::signals2

【讨论】:

    【解决方案2】:

    Qt 的signals and slots 似乎很符合您的描述。

    【讨论】:

      【解决方案3】:

      如果您向此事件系统添加智能指针,您应该处于良好状态。这个例子很像 C# 事件系统,没有许多可以在可下载代码之上轻松实现的保护措施。 http://www.theorangeday.com/tutorials/c-event-system-using-delegates/

      【讨论】: