65.9K
CodeProject 正在变化。 阅读更多。
Home

使用 C++ 实现模仿 C# 风格的多播事件

starIconstarIconstarIconstarIconstarIcon

5.00/5 (1投票)

2013年8月27日

CPOL
viewsIcon

17021

使用 C++ 实现模仿 C# 风格的多播事件

引言

虽然我们有很多方法来实现观察者模式,但继承的监听器在大多数 C++ 面向对象编程中被使用。一些熟悉 C#(或 Java 等)的程序员可能熟悉非继承的委托解决方案,这是在这些编程语言中最有效的方法。 在这个技巧中,我将向你展示一种用 C++ 模仿 C# 风格多播事件系统的方法。我的实现需要 fastdelegate 库。

实现

#ifndef __EVENT_H__
#define __EVENT_H__
#include <set>
#include "FastDelegate.h"
#include "FastDelegateBind.h"
namespace kks {
/**
 * @brief Base class of event
 */
template<typename HandlerT>
class _Event : public std::set<fastdelegate::FastDelegate<HandlerT> > {
public:
    typedef std::set<fastdelegate::FastDelegate<HandlerT> > BaseType;
    typedef fastdelegate::FastDelegate<HandlerT> Handler;
public:
    /**
     * @brief Register an event handler
     *
     * @param[in] handler - Event handler delegate
     * @return - True if registeration succeed
     */
    bool operator += (const Handler &handler) {
        if(BaseType::find(handler) != BaseType::end())
          return false;
        BaseType::insert(handler);
        return true;
    }
    /**
     * @brief Unregister an event handler
     *
     * @param[in] handler - Event handler delegate
     * @return - True if unregisteration succeed
     */
    bool operator -= (const Handler &handler) {
        if(BaseType::find(handler) == BaseType::end())
          return false;
        BaseType::erase(handler);
        return true;
    }
};
/**
 * @brief Event class
 */
template<typename Signature>
class Event;
/**
 * @brief Event class without arguments
 * @note This is a final class which you cannot derive from it
 */
template<>
class Event<void(void)> : public _Event<void(void)> {
public:
    typedef _Event<void(void)> BaseType;
public:
    Event() {
    }
    Event(const Event::Handler &handler) {
        this->operator += (handler);
    }
    /**
     * @brief Raise an event
     */
    void operator() (void) const {
        for(const_iterator it = begin(); it != end(); ++it) {
          Handler d = *it;
          d();
        }
    }
};
/**
 * @brief Event class with 1 argument
 * @note This is a final class which you cannot derive from it
 */
template<typename Arg1T>
class Event<void(Arg1T)> : public _Event<void(Arg1T)> {
public:
    typedef _Event<void(Arg1T)> BaseType;
public:
    Event() {
    }
    Event(const typename Event::Handler &handler) {
        this->operator += (handler);
    }
    /**
     * @brief Raise an event
     *
     * @param[in] arg1 - 1st argument
     */
    void operator() (Arg1T &arg1) {
        for(typename BaseType::iterator it = BaseType::begin(); it != BaseType::end(); ++it) {
          typename BaseType::Handler d = *it;
          d(arg1);
        }
    }
    /**
     * @brief Raise an event
     *
     * @param[in] arg1 - 1st argument
     */
    void operator() (Arg1T arg1) const {
        for(typename BaseType::const_iterator it = BaseType::begin(); it != BaseType::end(); ++it) {
          typename BaseType::Handler d = *it;
          d(arg1);
        }
    }
};
/**
 * @brief Event class with 2 arguments
 * @note This is a final class which you cannot derive from it
 */
template<typename Arg1T, typename Arg2T>
class Event<void(Arg1T, Arg2T)> : public _Event<void(Arg1T, Arg2T)> {
public:
    typedef _Event<void(Arg1T, Arg2T)> BaseType;
public:
    Event() {
    }
    Event(const typename Event::Handler &handler) {
        this->operator += (handler);
    }
    /**
     * @brief Raise an event
     *
     * @param[in] arg1 - 1st argument
     * @param[in] arg2 - 2nd argument
     */
    void operator() (Arg1T &arg1, Arg2T &arg2) {
        for(typename BaseType::iterator it = BaseType::begin(); it != BaseType::end(); ++it) {
          typename BaseType::Handler d = *it;
          d(arg1, arg2);
        }
    }
    /**
     * @brief Raise an event
     *
     * @param[in] arg1 - 1st argument
     * @param[in] arg2 - 2nd argument
     */
    void operator() (Arg1T arg1, Arg2T arg2) const {
        for(typename BaseType::const_iterator it = BaseType::begin(); it != BaseType::end(); ++it) {
          typename BaseType::Handler d = *it;
          d(arg1, arg2);
        }
    }
};
/**
 * @brief Event class with 3 arguments
 * @note This is a final class which you cannot derive from it
 */
template<typename Arg1T, typename Arg2T, typename Arg3T>
class Event<void(Arg1T, Arg2T, Arg3T)> : public _Event<void(Arg1T, Arg2T, Arg3T)> {
public:
    typedef _Event<void(Arg1T, Arg2T, Arg3T)> BaseType;
public:
    Event() {
    }
    Event(const typename Event::Handler &handler) {
        this->operator += (handler);
    }
    /**
     * @brief Raise an event
     *
     * @param[in] arg1 - 1st argument
     * @param[in] arg2 - 2nd argument
     * @param[in] arg3 - 3rd argument
     */
    void operator() (Arg1T &arg1, Arg2T &arg2, Arg3T &arg3) {
        for(typename BaseType::iterator it = BaseType::begin(); it != BaseType::end(); ++it) {
          typename BaseType::Handler d = *it;
          d(arg1, arg2, arg3);
        }
    }
    /**
     * @brief Raise an event
     *
     * @param[in] arg1 - 1st argument
     * @param[in] arg2 - 2nd argument
     * @param[in] arg3 - 3rd argument
     */
    void operator() (Arg1T arg1, Arg2T arg2, Arg3T arg3) const {
        for(typename BaseType::const_iterator it = BaseType::begin(); it != BaseType::end(); ++it) {
          typename BaseType::Handler d = *it;
          d(arg1, arg2, arg3);
        }
    }
};
// Add more if you wish.
}
#endif // __EVENT_H__  

Using the Code

按照以下步骤使用此代码页面

  1. 你可能应该创建一个事件类型定义,因为它能简化后续的编码和维护
    typedef Event<void(Arg1T, Arg2T, ...)> SomeEvent;
  2. 你可以使用该定义来声明一个事件
    SomeEvent OnSomeEvent;
  3. 如果发生某些事情,使用以下方式触发一个事件
    OnSomeEvent(Arg1, Arg2, ...);
  4. 要注册一个观察它的事件处理程序,请编写
    obj->SomeEvent += SomeEvent::Handler(Class*, &Class::Method);
  5. 不要忘记在某人不再观察该事件时,通过以下方式取消注册处理程序
    obj->SomeEvent -= SomeEvent::Handler(Class*, &Class::Method);
  6. 定义事件的一种常用模式是这样的
    Event<void(Sender*, EventArgsStruct*)>
    其中“Sender”是事件触发者,而“EventArgsStruct”是一个常见的结构体,它封装了详细的事件参数;这是一种源自 C# 的用法。
© . All rights reserved.