1、 C++实例:用C++模拟C#事件机制 C# delegate 本质上是一个函数的面对对象的封装, 在C++语言中函数分好多种,包括 全局函数,成员函数,函数对象(即functor,虽然不是函数,但由于行为像函数,所以归为函数一类),考试.大提示因此在C++里实现delegate的关键就是封装上述3类函数的不同,对外供应全都的接口,先来看一下delegate的实现。 template class Delegate { public:
2、 Delegate(){} virtual ~Delegate(){} public: typedef TReturn (*InvokerType)(TArgument args); // for global or static methods Delegate(TReturn (*pCallback)(TArgument)) :m_pInvoker(NULL) { Invoker::Bind(pCallback); m_pInvoker = Invoker::Invoke; } // for object member me
3、thods template Delegate(TObject* pObject, TReturn (TObject::*pCallback)(TArgument)) :m_pInvoker(NULL) { MemberInvoker::Bind(pObject,pCallback); m_pInvoker = MemberInvoker::Invoke; } // for functor methods template Delegate(TFunctor* pCallback) :m_pInvoker(NULL) {
4、 FunctorInvoker::Bind(pCallback); m_pInvoker = FunctorInvoker::Invoke; } TReturn operator() (TArgument args) { return m_pInvoker(args); } //implementations private: InvokerType m_pInvoker; }; delegate 本身就是一个函数对象,针对C++里3类函数供应了3个构造函数,每个构造函数的实现分别用到了一个帮助类别,分别是Invoker(用
5、于全局函数或者类的静态函数),MemberInvoker(用于类成员函数),FunctorInvoker(用于functor) ,这三个帮助类别主要用于在编译时保存函数类型,对象类型等信息。实现如下: template struct Invoker { typedef TReturn (*Method)(TArgument args); static TReturn Invoke(TArgument args) { return m_pCallback(args); } static void Bind(Method pCallback)
6、 { m_pCallback = pCallback; } private: static Method m_pCallback; }; template typename Invoker::Method Invoker::m_pCallback = NULL; template struct MemberInvoker { typedef TReturn (TObject::*MemberMethod)(TArgument); static TReturn Invoke(TArgument args) {
7、 return (m_pObject->*m_pCallback)(args); } static void Bind(TObject* pObject,MemberMethod pCallback) { m_pObject = pObject; m_pCallback = pCallback; } private: static TObject* m_pObject; static MemberMethod m_pCallback; }; template TObject* MemberInvoker::m_pObjec
8、t = NULL; template typename MemberInvoker::MemberMethod MemberInvoker::m_pCallback = NULL; template struct FunctorInvoker { typedef TFunctor* FunctorMethod; static TReturn Invoke(TArgument args) { return m_pCallback(args); } static void Bind(FunctorMethod pCallback)
9、 { m_pCallback = pCallback; } private: static FunctorMethod m_pCallback; }; template typename FunctorInvoker::FunctorMethod FunctorInvoker::m_pCallback = NULL; 至此,一个完整的delegate实现完毕,我们可以用它来实现event 了。 event实现如下,为了实现多播用std::list保存多个deledate: template class Event {
10、 public: typedef TReturn ReturnValue; typedef TArgument EventArgs; typedef Delegate EventHandler; public: Event(){} virtual ~Event(){} public: ReturnValue GetReturnValue(const EventHandler } ReturnValue operator() (EventArgs/* const for (std::list::iterator i = m_H
11、andler.begin(); i != m_Handler.end(); ++i) { RetValue = (*i)(rhs); m_ReturnValue[(*i)] = RetValue; } return RetValue; } Event return *this; } Event return *this; } private: std::list m_Handler; std::map m_ReturnValue; }; event重载了+=, -=操作符,使用上完全跟C#原生的event操作根本一样。event实际上就是一个多播delegate,假如不需要多播,直接使用delegate就可以了。 目前的实现还有一些小问题: 1.目前event不支持void返回类型,其实只要写一个event偏特化就可,由于我是在VC6下写的代码,而VC6不支持模板偏特化 2. 由于C++语言对模板的一些限制,不得以在头文件中定义了一些静态成员变量,所以当在多个.cpp文件中包含这个头文件时会有链接错误,VC下可以使用_declspec(selectany)解决这个问题,别的编译器我就不知道了。






