首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >C++事件系统设计

C++事件系统设计
EN

Stack Overflow用户
提问于 2010-11-09 05:18:49
回答 3查看 11.1K关注 1票数 4

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

  1. 速度
  2. 易用性
  3. 类型安全
  4. 友好销毁

我所说的“友好破坏”是指当其中一个用户被破坏时,用户需要管理他们的断开:

  • 事件不应调用已销毁的订阅服务器。
  • 订阅者不应该能够从已销毁的事件中注销。

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

用户观点:

代码语言:javascript
复制
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()); 
}

内部代码:

代码语言:javascript
复制
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#中)

欢迎任何反馈意见。

谢谢。

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2010-11-09 07:29:40

如果您希望线程安全,请使用*信号*信号2

票数 8
EN

Stack Overflow用户

发布于 2010-11-09 09:19:50

Qt的信号和插槽似乎很符合您的描述。

票数 3
EN

Stack Overflow用户

发布于 2012-12-21 17:30:48

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

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/4130755

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档