事件是面向组件开发的必要特性之一,但C++不直接支持事件,没关系,我自己实现了一个,感觉很好用,分享给大家!
最开始打算用函数指针模拟事件,但由于C++中成员函数指针不能和void*相互强转,而且typedef中不能含有模板,所以才不得已以接口继承实现。这样效果也不错 :)
一. 先看看事件接口定义和实现
上面的实现是浅显易懂的,关键是要注意IEventPublisher的双重身份-- 事件发布方最好发布IEvent指针给外部,而该指针实际指向的是一个EventPublisher对象,这是为了避免外部直接调用IEventActivator接口的方法。
二. 一个定时器类Timer,演示如何发布事件。想必大家都知道定时器的用途了哦,这个Timer就像C#中的Timer类一样。
最开始打算用函数指针模拟事件,但由于C++中成员函数指针不能和void*相互强转,而且typedef中不能含有模板,所以才不得已以接口继承实现。这样效果也不错 :)
一. 先看看事件接口定义和实现
#ifndefIEVENT_H
#defineIEVENT_H
/*
以下各基础设施是在C++中事件机制的完整实现,事件是面向组件开发的必要特性之一。
创作者:sky
时间:2005.06.22
修订时间:2005.06.22
*/
#include"../Collection/SafeArrayList.h"
template<classSenderType,classParaType>classEventPublisher;
classNullType
{
};
//IEventHandler是事件处理句柄,预定事件的类从此接口继承以实现事件处理函数
template<classSenderType,classParaType>
interfaceIEventHandler
{
public:
virtual~IEventHandler(){}
private:
virtualvoidHandleEvent(SenderTypesender,ParaTypepara)=0;
friendclassEventPublisher<SenderType,ParaType>;
};
//IEvent事件预定方通过此接口预定事件
template<classSenderType,classParaType>
interfaceIEvent
{
public:
virtual~IEvent(){}
virtualvoidRegister(IEventHandler<SenderType,ParaType>*handler)=0;
virtualvoidUnRegister(IEventHandler<SenderType,ParaType>*handler)=0;
};
//IEventActivator事件发布方通过此接口触发事件
template<classSenderType,classParaType>
interfaceIEventActivator
{
public:
virtual~IEventActivator(){}
virtualvoidInvoke(SenderTypesender,ParaTypepara)=0;
virtualintHandlerCount()=0;
virtualIEventHandler<SenderType,ParaType>*GetHandler(intindex)=0;
};
//IEventPublisher事件发布方发布事件相当于就是发布一个IEventPublisher派生类的对象
//不过仅仅将该对象的IEvent接口发布即可。
template<classSenderType,classParaType>
interfaceIEventPublisher:publicIEvent<SenderType,ParaType>,publicIEventActivator<SenderType,ParaType>
{
};
//EventPublisher是IEventPublisher的默认实现
template<classSenderType,classParaType>
classEventPublisher:publicIEventPublisher<SenderType,ParaType>
{
private:
SafeArrayList<IEventHandler<SenderType,ParaType>>handerList;
IEventHandler<SenderType,ParaType>*innerHandler;
public:
voidRegister(IEventHandler<SenderType,ParaType>*handler)
{
this->handerList.Add(handler);
}
voidUnRegister(IEventHandler<SenderType,ParaType>*handler)
{
this->handerList.Remove(handler);
}
voidInvoke(SenderTypesender,ParaTypepara)
{
intcount=this->handerList.Count();
for(inti=0;i<count;i++)
{
IEventHandler<SenderType,ParaType>*handler=this->handerList.GetElement(i);
handler->HandleEvent(sender,para);
}
}
intHandlerCount()
{
returnthis->handerList.Count();
}
IEventHandler<SenderType,ParaType>*GetHandler(intindex)
{
returnthis->handerList.GetElement(index);
}
};
#endif
#defineIEVENT_H
/*
以下各基础设施是在C++中事件机制的完整实现,事件是面向组件开发的必要特性之一。
创作者:sky
时间:2005.06.22
修订时间:2005.06.22
*/
#include"../Collection/SafeArrayList.h"
template<classSenderType,classParaType>classEventPublisher;
classNullType
{
};
//IEventHandler是事件处理句柄,预定事件的类从此接口继承以实现事件处理函数
template<classSenderType,classParaType>
interfaceIEventHandler
{
public:
virtual~IEventHandler(){}
private:
virtualvoidHandleEvent(SenderTypesender,ParaTypepara)=0;
friendclassEventPublisher<SenderType,ParaType>;
};
//IEvent事件预定方通过此接口预定事件
template<classSenderType,classParaType>
interfaceIEvent
{
public:
virtual~IEvent(){}
virtualvoidRegister(IEventHandler<SenderType,ParaType>*handler)=0;
virtualvoidUnRegister(IEventHandler<SenderType,ParaType>*handler)=0;
};
//IEventActivator事件发布方通过此接口触发事件
template<classSenderType,classParaType>
interfaceIEventActivator
{
public:
virtual~IEventActivator(){}
virtualvoidInvoke(SenderTypesender,ParaTypepara)=0;
virtualintHandlerCount()=0;
virtualIEventHandler<SenderType,ParaType>*GetHandler(intindex)=0;
};
//IEventPublisher事件发布方发布事件相当于就是发布一个IEventPublisher派生类的对象
//不过仅仅将该对象的IEvent接口发布即可。
template<classSenderType,classParaType>
interfaceIEventPublisher:publicIEvent<SenderType,ParaType>,publicIEventActivator<SenderType,ParaType>
{
};
//EventPublisher是IEventPublisher的默认实现
template<classSenderType,classParaType>
classEventPublisher:publicIEventPublisher<SenderType,ParaType>
{
private:
SafeArrayList<IEventHandler<SenderType,ParaType>>handerList;
IEventHandler<SenderType,ParaType>*innerHandler;
public:
voidRegister(IEventHandler<SenderType,ParaType>*handler)
{
this->handerList.Add(handler);
}
voidUnRegister(IEventHandler<SenderType,ParaType>*handler)
{
this->handerList.Remove(handler);
}
voidInvoke(SenderTypesender,ParaTypepara)
{
intcount=this->handerList.Count();
for(inti=0;i<count;i++)
{
IEventHandler<SenderType,ParaType>*handler=this->handerList.GetElement(i);
handler->HandleEvent(sender,para);
}
}
intHandlerCount()
{
returnthis->handerList.Count();
}
IEventHandler<SenderType,ParaType>*GetHandler(intindex)
{
returnthis->handerList.GetElement(index);
}
};
#endif
二. 一个定时器类Timer,演示如何发布事件。想必大家都知道定时器的用途了哦,这个Timer就像C#中的Timer类一样。
#ifndefTIMER_H
#defineTIMER_H
/*
Timer定时器,每经过一段指定时间就触发事件
创作者:sky
时间:2005.06.22
修订时间:2005.06.22
*/
#include"IEvent.h"
#include"Thread.h"
voidTimerThreadStart(void*para);
classTimer
{
private:
intspanInMillSecs;
volatileboolisStop;
volatilebooltimerThreadDone;
public:
friendvoidTimerThreadStart(void*para);
IEvent<Timer*,NullType>*TimerTicked;
Timer(intspan_InMillSecs)
{
this->isStop=true;
this->timerThreadDone=true;
this->spanInMillSecs=span_InMillSecs;
this->TimerTicked=newEventPublisher<Timer*,NullType>;
}
~Timer()
{
this->Stop();
deletethis->TimerTicked;
}
voidStart()
{
if(!this->isStop)
{
return;
}
this->isStop=false;
Threadthread;
thread.Start(TimerThreadStart,this);
//unsignedintdwThreadId;
//HANDLEhThread=(HANDLE)_beginthreadex(NULL,0,(unsignedint(_stdcall*)(void*))&TimerThreadStart,this,0,&dwThreadId);
}
voidStop()
{
if(this->isStop)
{
return;
}
this->isStop=true;
//等待工作线程退出
while(!this->timerThreadDone)
{
Sleep(200);
}
}
private:
voidWorkerThread()
{
this->timerThreadDone=false;
while(!this->isStop)
{
Sleep(this->spanInMillSecs);
if(this->isStop)
{
break;
}
NullTypenullObj;
((EventPublisher<Timer*,NullType>*)this->TimerTicked)->Invoke(this,nullObj);
}
this->timerThreadDone=true;
}
};
voidTimerThreadStart(void*para)
{
Timer*timer=(Timer*)para;
timer->WorkerThread();
}
#endif
#defineTIMER_H
/*
Timer定时器,每经过一段指定时间就触发事件
创作者:sky
时间:2005.06.22
修订时间:2005.06.22
*/
#include"IEvent.h"
#include"Thread.h"
voidTimerThreadStart(void*para);
classTimer
{
private:
intspanInMillSecs;
volatileboolisStop;
volatilebooltimerThreadDone;
public:
friendvoidTimerThreadStart(void*para);
IEvent<Timer*,NullType>*TimerTicked;
Timer(intspan_InMillSecs)
{
this->isStop=true;
this->timerThreadDone=true;
this->spanInMillSecs=span_InMillSecs;
this->TimerTicked=newEventPublisher<Timer*,NullType>;
}
~Timer()
{
this->Stop();
deletethis->TimerTicked;
}
voidStart()
{
if(!this->isStop)
{
return;
}
this->isStop=false;
Threadthread;
thread.Start(TimerThreadStart,this);
//unsignedintdwThreadId;
//HANDLEhThread=(HANDLE)_beginthreadex(NULL,0,(unsignedint(_stdcall*)(void*))&TimerThreadStart,this,0,&dwThreadId);
}
voidStop()
{
if(this->isStop)
{
return;
}
this->isStop=true;
//等待工作线程退出
while(!this->timerThreadDone)
{
Sleep(200);
}
}
private:
voidWorkerThread()
{
this->timerThreadDone=false;
while(!this->isStop)
{
Sleep(this->spanInMillSecs);
if(this->isStop)
{
break;
}
NullTypenullObj;
((EventPublisher<Timer*,NullType>*)this->TimerTicked)->Invoke(this,nullObj);
}
this->timerThreadDone=true;
}
};
voidTimerThreadStart(void*para)
{
Timer*timer=(Timer*)para;
timer->WorkerThread();
}
#endif
上面的示例清晰地说明了如何发布一个事件,如何在适当的时候触发事件,接下来看看如何预定事件。
三. 预定事件例子
classTimerEventExample:publicIEventHandler<Timer*,NullType>,CriticalSection
{
private:
Timer*timer;
public:
TimerEventExample(intcheckSpan)
{
this->timer=newTimer(checkSpan);
this->timer->TimerTicked->Register(this);
}
~TimerEventExample()
{
deletethis->timer;
}
private:
//处理定时事件
voidHandleEvent(Timer*sender,NullTypepara)
{
cout<<"Timeticked!"<<endl;
}
};
{
private:
Timer*timer;
public:
TimerEventExample(intcheckSpan)
{
this->timer=newTimer(checkSpan);
this->timer->TimerTicked->Register(this);
}
~TimerEventExample()
{
deletethis->timer;
}
private:
//处理定时事件
voidHandleEvent(Timer*sender,NullTypepara)
{
cout<<"Timeticked!"<<endl;
}
};
到这里,已经将C++中的事件机制的实现及使用讲清楚了。C#提供了很多便利的基础设施来支持组件开发,而在C++中,这些基础设施需要自己动手来构建,在拥有了这些设施之后,相信使用C++进行组件开发会轻松一点。
突然想起来,这里是.NET专区,这篇文章放在这里是否合适?犹豫了一下,还是决定留下来。也许可以对那些有C++基础的.NET开发者有所帮助,也算是对事件的内部机理的另一种展现吧。