使用基于接口的委托实现C++的事件机制
介绍一种使用 C# 风格委托的 C++ 简单事件机制。
引言
本文介绍了一种在 C++ 中非常简单且方便的事件机制。在许多情况下,由于其复杂性,C++ 中的委托很难理解。 附带的代码是一个示例,它使用了 C# 委托风格和 Java 内部类回调风格的结合。它可以向您展示一个简单的事件机制示例。
事件处理
// delegate
struct ISampleEventHandler : public IEventHandler
{
    virtual void callback( IUnknown* object, const SampleEventArgs& e ) = 0;
    typedef SampleEventArgs _EventArgs; // passive polymorphism using typedef
};
// event
template<typename T>
class Event
{
public:
    void invoke(IUnknown* object, const EventArgs& e = EventArgs::Empty)
    {
        std::set<T*>::iterator iter;
        for (iter = m_EventHandler.begin();
            iter != m_EventHandler.end();
            ++iter)
        {
            // this code can promise the type-safe callback because
            // of the polymorphism using typedef in delegate
            (*iter)->callback(object, static_cast<const T::_EventArgs&>(e));
        }
    }
    void operator+=(T* eventHandler)
    {
        m_EventHandler.insert(eventHandler);
    }
    void operator-=(T* eventHandler)
    {
        m_EventHandler.erase(eventHandler);
    }
protected:
    std::set<T*> m_EventHandler;
};
Using the Code
我们需要一个抽象父类来标识事件发送者。
class IUnknown
{
public:
 virtual ~IUnknown() {}
 virtual std::string name() = 0;
};
这是事件发送类
class Callee : public IUnknown
{
public:
// declare the event.
 Event<ISampleEventHandler> SampleEvent;
public:
 void test()
 {
  SampleEventArgs e;
  e.sampleData = 10;
  e.sampleData2 = 20;
// event occur.
  SampleEvent.invoke(this, e);
 }
 std::string name() { return "callee"; }
};
这是事件接收类
class Caller : public IUnknown
{
public:
 Caller()
 {
// register Caller's inner class object to Callee.
  m_Callee.SampleEvent += &sampleEventHandler;
 }
 ~Caller()
 {
// unregister Caller's inner class object from Callee.
  m_Callee.SampleEvent -= &sampleEventHandler;
 }
 void test()
 {
  m_Callee.test();
 }
private:
 void print(IUnknown* object, const SampleEventArgs& e)
 {
  std::cout << object->name().c_str() << std::endl;
  std::cout << e.sampleData << std::endl;
  std::cout << e.sampleData2 << std::endl;
 }
 std::string name() { return "caller"; }
private:
 class SampleEventHandler : public ISampleEventHandler
 {
  void callback( IUnknown* object, const SampleEventArgs& e )
  {
    // to access outer class's member function.
    Caller* outer = reinterpret_cast<Caller*>((char*)this - 
                       offsetof(Caller, sampleEventHandler));
    outer->print(object, e);
  }
 } sampleEventHandler;
private:
 Callee m_Callee;
};
关注点
您可以很容易地找到使用委托的好处。它可以打破每个类的循环依赖——“调用者”依赖于“被调用者”,但“被调用者”不依赖于任何类。
历史
- 2007. 03. 29 - 首次发布。




