C++实例:用C++模拟C#事件机制

C++实例:用C++模拟C#事件机制,第1张

C++实例:用C++模拟C#事件机制,第2张

C#中的事件机制可以方便地实现设计模式中的观察者模式。C#提供了委托和事件来实现这种机制。其实只要delagate能实现事件效果,事件语法完全没必要,因为delegate是组播的。本文提供了一个C++版本的实现,与C#的原生事件机制只有一点不同。我实现的委托是单播的(以避免委托和事件的功能重复)。
C#委托本质上是函数的面向对象封装。在C++语言中,有很多种函数,包括全局函数、成员函数、函数对象(即,仿函数,虽然不是函数,但被归类为函数,因为它们的行为像函数),以及考试。大提示。因此,在C++中实现delegate的关键是封装上述三类函数的差异,并对外提供一致的接口。
template
class Delegate
{
public:
Delegate(){ }
virtual ~ Delegate(){ }
public:
typedef TReturn(* invoker type)(targumentargs);
//对于全局或静态方法
Delegate(TReturn(* pcall back)(TArgument))
:m _ pInvoker(NULL)
{
Invoker::Bind(pcall back);
m _ pInvoker = Invoker::Invoke;
}
// for object成员方法
template
Delegate(to object * po object,TReturn(to object::* pcall back)(TArgument))
:m _ pInvoker(NULL)
{
member invoker::Bind(po object,pcall back);
m _ pInvoker = member invoker::Invoke;
}
//for functor methods
template
Delegate(TFunctor * pcall back)
:m _ pInvoker(NULL)
{
FunctorInvoker::Bind(pcall back);
m _ pInvoker = FunctorInvoker::Invoke;
}
TReturn operator()(targumentargs)
{
return m _ pInvoker(args);
}
//实现
private:
invoker type m _ pInvoker;
};
委托本身就是一个函数对象。它为C++中的三种类型的函数提供了三个构造函数。每个构造函数都用一个辅助类别实现,即Invoker(用于类的全局函数或静态函数)、MemberInvoker(用于类成员函数)和FunctorInvoker(用于functor)。这三个辅助类别主要用于在编译时保存函数类型、对象类型等信息。实现如下:
template
struct invoker
{
typedef treturn(* method)(t argument args);
static TReturn Invoke(TArgument args)
{
return m _ pcall back(args);
}
静态void Bind(方法pcall back)
{
m _ pcall back = pcall back;
}
private:
静态方法m _ pCallback
};
template
typename Invoker::Method Invoker::m _ pcall back = NULL;
template
struct member invoker
{
typedef TReturn(to object::* member method)(TArgument);
static TReturn Invoke(targumentargs)
{
return(m _ po object--> * m _ pcall back)(args);
}
静态void Bind(to object * po object,member method pcall back)
{
m _ po object = po object;
m _ pcall back = pcall back;
}
private:
static to object * m _ po object;
static member method m _ pcall back;
};
template
to object * member invoker::m _ po object = NULL;
template
typename member invoker::member method member invoker::m _ pcall back = NULL;
template
struct functor invoker
{
typedef TFunctor * functor method;
static TReturn Invoke(TArgument args)
{
return m _ pcall back(args);
}
静态void Bind(functor method pcall back)
{
m _ pcall back = pcall back;
}
private:
static functor method m _ pcall back;
};
template
typename FunctorInvoker::functor method FunctorInvoker::m _ pcall back = NULL;
至此,已经实现了一个完整的委托,我们可以用它来实现事件。
事件的实现如下。为了实现组播,使用std::list保存多个dele date:
template < classtreturn,classtarrgument >
class event
public:
typedef treturn返回值;
typedef targumenteventargs;
typedef委托事件处理程序;
public:
Event(){ }
virtual ~ Event(){ }
public:
return value get return value(const EventHandler & RHS)
{
return m _ return value[RHS];
}
return value operator()(EventArgs/* const & */RHS)
{
return value ret value;
for(STD::list::iterator I = m _ handler . begin();我!= m _ handler . end();++ I)
{
RetValue =(* I)(RHS);
m _ return value[(* I)]= ret value;
}
return RetValue;
}
Event & operator+=(EventHandler/* const & */RHS)
{
m _ handler . push _ back(RHS);
return * this;
}
Event & operator-=(EventHandler/* const & */RHS)
{
m _ handler . remove(RHS);
return * this;
}
private:
STD::list m _ Handler;
STD::map m _ return value;
};
event重载了+=,-=运算符,其用法与C#的原生事件操作基本相同。事件实际上是一个多播委托。如果不需要组播,就用delegate。
目前的实现还有一些小问题:
1。目前,事件不支持void返回类型。其实你只需要写一个事件专门化,因为我是用VC6写的代码,VC6不支持模板专门化
2。由于C++语言对模板的一些限制,一些静态成员变量一定不能在头文件中定义。所以当这个头文件包含在多个。cpp文件,会有链接错误。可以用VC下的_declspec(selectany)来解决这个问题。其他编译器我就不知道了。

位律师回复
DABAN RP主题是一个优秀的主题,极致后台体验,无插件,集成会员系统
白度搜_经验知识百科全书 » C++实例:用C++模拟C#事件机制

0条评论

发表评论

提供最优质的资源集合

立即查看 了解详情