C ++事件系统设计

时间:2010-11-09 05:18:50

标签: c++ events delegates

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

  1. 速度
  2. 易用性
  3. 类型安全
  4. 友善毁灭
  5. 通过“友好销毁”我的意思是事件和订户需要在其中一个被破坏时管理他们的断开连接:

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

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

    用户观点:

    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#更漂亮的设计)

    欢迎任何反馈。

    感谢。

3 个答案:

答案 0 :(得分:8)

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

答案 1 :(得分:3)

Qt的signals and slots似乎很适合你的描述。

答案 2 :(得分:0)

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