使用基于接口的委托实现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 - 首次发布。