转自:http://www.cnblogs.com/zhuweisky/archive/2005/09/10/234152.html
C++ 事件机制实现
事件是面向组件开发的必要特性之一,但C++不直接支持事件,没关系,我自己实现了一个,感觉很好用,分享给大家! 最开始打算用函数指针模拟事件,但由于C++中成员函数指针不能和void*相互强转,而且 typedef中不能含有模板,所以才不得已以接口继承实现。这样效果也不错 :)一. 先看看事件接口定义和实现
#ifndef IEVENT_H
#define
IEVENT_H
/*
以下各基础设施是在C++中事件机制的完整实现,事件是面向组件开发的必要特性之一。 创 作 者:sky 时 间:2005.06.22 修订时间:2005.06.22
*/
#include
"
../Collection/SafeArrayList.h
"
template
<
class
SenderType ,
class
ParaType
>
class
EventPublisher ;
class
NullType{};
//
IEventHandler 是事件处理句柄,预定事件的类从此接口继承以实现事件处理函数
template
<
class
SenderType ,
class
ParaType
>
interface
IEventHandler{
public
:
virtual
~
IEventHandler(){}
private
:
virtual
void
HandleEvent(SenderType sender ,ParaType para)
=
0
; friend
class
EventPublisher
<
SenderType ,ParaType
>
;};
//
IEvent 事件预定方通过此接口预定事件
template
<
class
SenderType ,
class
ParaType
>
interface
IEvent{
public
:
virtual
~
IEvent(){}
virtual
void
Register (IEventHandler
<
SenderType ,ParaType
>*
handler)
=
0
;
virtual
void
UnRegister(IEventHandler
<
SenderType ,ParaType
>*
handler)
=
0
;};
//
IEventActivator 事件发布方通过此接口触发事件
template
<
class
SenderType ,
class
ParaType
>
interface
IEventActivator{
public
:
virtual
~
IEventActivator(){}
virtual
void
Invoke(SenderType sender ,ParaType para)
=
0
;
virtual
int
HandlerCount()
=
0
;
virtual
IEventHandler
<
SenderType ,ParaType
>*
GetHandler(
int
index)
=
0
;};
//
IEventPublisher 事件发布方发布事件相当于就是发布一个IEventPublisher派生类的对象
//
不过仅仅将该对象的IEvent接口发布即可。
template
<
class
SenderType ,
class
ParaType
>
interface
IEventPublisher :
public
IEvent
<
SenderType ,ParaType
>
,
public
IEventActivator
<
SenderType ,ParaType
>
{};
//
EventPublisher是IEventPublisher的默认实现
template
<
class
SenderType ,
class
ParaType
>
class
EventPublisher :
public
IEventPublisher
<
SenderType ,ParaType
>
{
private
: SafeArrayList
<
IEventHandler
<
SenderType ,ParaType
>
>
handerList ; IEventHandler
<
SenderType ,ParaType
>*
innerHandler ;
public
:
void
Register(IEventHandler
<
SenderType ,ParaType
>*
handler) {
this
->
handerList.Add(handler) ; }
void
UnRegister(IEventHandler
<
SenderType ,ParaType
>*
handler) {
this
->
handerList.Remove(handler) ; }
void
Invoke(SenderType sender ,ParaType para) {
int
count
=
this
->
handerList.Count() ;
for
(
int
i
=
0
;i
<
count ;i
++
) { IEventHandler
<
SenderType ,ParaType
>*
handler
=
this
->
handerList.GetElement(i) ; handler
->
HandleEvent(sender ,para) ; } }
int
HandlerCount() {
return
this
->
handerList.Count() ; } IEventHandler
<
SenderType ,ParaType
>*
GetHandler(
int
index) {
return
this
->
handerList.GetElement(index) ; }};
#endif
上面的实现是浅显易懂的,关键是要注意
IEventPublisher的双重身份-- 事件发布方最好发布IEvent指针给外部,而该指针实际指向的是一个EventPublisher对象,这是为了避免外部直接调用IEventActivator接口的方法。二. 一个定时器类Timer,演示如何发布事件。想必大家都知道定时器的用途了哦,这个Timer就像C#中的Timer类一样。
#ifndef TIMER_H
#define
TIMER_H
/*
Timer 定时器,每经过一段指定时间就触发事件 创 作 者:sky 时 间:2005.06.22 修订时间:2005.06.22
*/
#include
"
IEvent.h
"
#include
"
Thread.h
"
void
TimerThreadStart(
void
*
para) ;
class
Timer{
private
:
int
spanInMillSecs ;
volatile
bool
isStop ;
volatile
bool
timerThreadDone ;
public
: friend
void
TimerThreadStart(
void
*
para) ; IEvent
<
Timer
*
,NullType
>*
TimerTicked ; Timer(
int
span_InMillSecs) {
this
->
isStop
=
true
;
this
->
timerThreadDone
=
true
;
this
->
spanInMillSecs
=
span_InMillSecs ;
this
->
TimerTicked
=
new
EventPublisher
<
Timer
*
,NullType
>
; }
~
Timer() {
this
->
Stop() ; delete
this
->
TimerTicked ; }
void
Start() {
if
(
!
this
->
isStop) {
return
; }
this
->
isStop
=
false
; Thread thread ; thread.Start(TimerThreadStart ,
this
) ;
//
unsigned int dwThreadId ;
//
HANDLE hThread = (HANDLE)_beginthreadex(NULL, 0 , (unsigned int (_stdcall*)(void*))&TimerThreadStart , this, 0, &dwThreadId);
}
void
Stop() {
if
(
this
->
isStop) {
return
; }
this
->
isStop
=
true
;
//
等待工作线程退出
while
(
!
this
->
timerThreadDone) { Sleep(
200
) ; } }
private
:
void
WorkerThread() {
this
->
timerThreadDone
=
false
;
while
(
!
this
->
isStop) { Sleep(
this
->
spanInMillSecs) ;
if
(
this
->
isStop) {
break
; } NullType nullObj ; ((EventPublisher
<
Timer
*
,NullType
>*
)
this
->
TimerTicked)
->
Invoke(
this
,nullObj) ; }
this
->
timerThreadDone
=
true
; }};
void
TimerThreadStart(
void
*
para){ Timer
*
timer
=
(Timer
*
)para ; timer
->
WorkerThread() ;}
#endif
上面的示例清晰地说明了如何发布一个事件,如何在适当的时候触发事件,接下来看看如何预定事件。三. 预定事件例子
class
TimerEventExample :
public
IEventHandler
<
Timer
*
,NullType
>
,CriticalSection{
private
: Timer
*
timer ;
public
: TimerEventExample(
int
checkSpan) {
this
->
timer
=
new
Timer(checkSpan) ;
this
->
timer
->
TimerTicked
->
Register(
this
) ; }
~
TimerEventExample() { delete
this
->
timer ; }
private
:
//
处理定时事件
void
HandleEvent(Timer
*
sender ,NullType para) { cout
<<
"
Time ticked !
"
<<
endl ; }};
到这里,已经将C++中的事件机制的实现及使用讲清楚了。C#提供了很多便利的基础设施来支持组件开发,而在C++中,这些基础设施需要自己动手来构建,在拥有了这些设施之后,相信使用C++进行组件开发会轻松一点。