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

使用基于接口的委托实现C++的事件机制

starIconstarIconemptyStarIconemptyStarIconemptyStarIcon

2.00/5 (6投票s)

2007年3月29日

CPOL
viewsIcon

34006

downloadIcon

303

介绍一种使用 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 - 首次发布。
© . All rights reserved.