C ++事件系统设计 [英] C++ event system design

查看:151
本文介绍了C ++事件系统设计的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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


  1. 速度

  2. 易于使用

  3. 类型安全

  4. 友好破坏

友好破坏我的意思是事件和用户需要管理他们的断开连接,当其中一个被破坏时:




  • 事件不应该调用已被销毁的订户

  • 订阅者无法取消注册已被销毁的活动。



我想知道有没有人会比我想到的更好的设计:



用户观点:

  struct ClickEventArg {}; 

// ---------------------------------------- ---------------------------------
class Button
{
public:
事件< ClickEventArg&>点击;

void SendClick(ClickEventArg& arg)
{
Clicked(this,arg);
}
};

// ---------------------------------------- ---------------------------------
class User
{
public:
void注册(按钮*按钮)
{
button-> Clicked.Subscribe(m_suscriber,this,& User :: OnButtonClicked);
}

void OnButtonClicked(void * sender,ClickEventArg& arg)
{
std :: cout<< 按钮点击;
}

private:
EventSubscriber m_suscriber;
};

// ---------------------------------------- ---------------------------------
void Test()
{
Button * button = new Button();
用户* user = new User();
user->注册(按钮);
button-> SendClick(ClickEventArg());
删除用户;
button-> SendClick(ClickEventArg());
}

内部代码:

  class EventSubscriber; 

// ---------------------------------------- ---------------------------------
class BaseEvent
{
public:
virtual void UnSubscribe(EventSubscriber& subscriber)= 0;
};

// ---------------------------------------- ---------------------------------
template< class TEventArgs>
class事件: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);
}

模板< 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>用户地图;
订阅者地图m_subscribers;
};

// ---------------------------------------- ---------------------------------
class EventSubscriber
{
template< ; class TEventArgs>朋友班活动;

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);
(EventSet :: iterator it = copy.begin(); it!= copy.end(); ++ it)
{
(* it) - > UnSubscribe(*这个);
}
}

typedef std :: set< BaseEvent *>事件集
EventSet m_subscriptions;
};

您可能会注意到我使用了这篇文章中的快速代表 http://www.codeproject.com/KB/cpp/FastDelegate.aspx



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



欢迎任何反馈。



谢谢。

解决方案

使用boost::signals boost :: signals2 如果你想要线程安全。


I need to use an event system in C++. I have mainly four requirements :

  1. Speed
  2. Ease of use
  3. Type Safety
  4. Friendly Destruction

By "Friendly Destruction" I mean the event and the subscriber need to manage their disconnection when one of them get destroyed :

  • An event shouldn't call a subscriber that has been destroyed.
  • A subscriber shouldn't be able to unregister from an event that has been destroyed.

I wonder if anyone would have a nicer design than what I came up with :

User point of view :

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()); 
}

Internal code :

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;
};

You may notice I used the fast delegates from this article http://www.codeproject.com/KB/cpp/FastDelegate.aspx.

The EventSubscriber class is needed for the "Friendly Destruction" aspect. (Otherwise I would have used a prettier design like in C#)

Any feedback is welcome.

Thanks.

解决方案

Use boost::signals or boost::signals2 if you want thread safety.

这篇关于C ++事件系统设计的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆