资源描述
C++实例:用C++模拟C#事件机制
C# delegate 本质上是一个函数的面对对象的封装, 在C++语言中函数分好多种,包括 全局函数,成员函数,函数对象(即functor,虽然不是函数,但由于行为像函数,所以归为函数一类),考试.大提示因此在C++里实现delegate的关键就是封装上述3类函数的不同,对外供应全都的接口,先来看一下delegate的实现。
template
class Delegate
{
public:
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 methods
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)
{
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(用于全局函数或者类的静态函数),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)
{
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)
{
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_pObject = 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)
{
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
{
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_Handler.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)解决这个问题,别的编译器我就不知道了。
展开阅读全文