【转贴】 让C++也来支持事件

转贴【http://blog.csdn.net/glock18/archive/2004/07/14/41566.aspx
面向对象发展到今天,人们已经不满足于对一个事物的描述仅停留在属性和方法上了。事件也作为对象的基本组成部分,被新兴的面向对象语言所采纳。 所谓事件就是一个对象在某个特定的条件下触发通知对象的创建者,由创建者来进行相应的处理。我们可以看到事件的真实处理过程并不被包装在对象里。在java,c#,dephi等语言中都提供了对事件的支持,或者以关键字的形式,或者以类库的形式。而c++中见不到任何关于事件的关键字和类库,难道c++就无法拥有事件这个特性吗?只要动动脑筋就没有难事。现在我们就让c++也来支持事件。
这里仅从语言上考虑,而不使用任何平台相关的特性(消息,事件对象...)。因此我拿出两种实现方法,一种是采用函数指针,另一种采用虚函数。
1. 采用函数指针方式,代码如下:

//定义事件函数的类型
typedef void (*EOnBeforeInvoke)();

typedef
void (*EOnAfterInvoke)();
//一个拥有事件的类
class CSomeObject1

{

public
:
 //定义事件
EOnBeforeInvoke OnBeforeInvoke; //调用前事件
EOnAfterInvoke  OnAfterInvoke;
  //调用后事件
public:
 CSomeObject1
()
 {

  OnBeforeInvoke = NULL;
  OnAfterInvoke = NULL
;
 }

 void
Invoke()
 {

  //触发OnBeforeInvoke事件
  if (OnBeforeInvoke != NULL)
   OnBeforeInvoke();
 
  cout << "CSomeObject1::Invoke()" <

  //触发OnAfterInvoke事件
  if (OnAfterInvoke != NULL)
   OnAfterInvoke
();
 }
};

//CSomeObject1对象的创建者类
class CEventTest1
{

 CSomeObject1 m_objSome;

 static void  OnBeforeInvoke()
 {

  cout<< "调用前..." < }

 static
void  OnAfterInvoke()
 {

  cout<< "调用后..." < }

 //安装事件
void InstallEvents()
 {

  m_objSome.OnBeforeInvoke = OnBeforeInvoke;
  m_objSome.OnAfterInvoke = OnAfterInvoke
;
 }

 //卸载事件
void UninstallEvents()
 {

  m_objSome.OnBeforeInvoke = NULL;
  m_objSome.OnAfterInvoke = NULL
;
 
 }

public:
 CEventTest1
()
 {

  InstallEvents
();
 }
 
 ~
CEventTest1
()
 {

  UninstallEvents
();
 }

 void Invoke()
 {

  m_objSome.Invoke
();
 }
};

 
int
main(int argc, char* argv[])
{

 CEventTest1 test1;
 test1.Invoke
();
}

        记得当年在TurboC下编程时,虽然没有c++,但依然可以写出面向对象的代码,就是利用struct里添加函数指针域的方式,来实现现在c++中的class。如今函数指针依然有用武之地。

2. 采用虚拟函数的形式,代码如下:

//事件接口
class  __declspec(novtable) ISomeObject2Events
{

 friend class
CSomeObject2;
protected
:
 virtual
void OnBeforeInvoke();
 virtual
void OnAfterInvoke();
};

//一个拥有事件的类
class CSomeObject2
{

public
:
 ISomeObject2Events * m_pEvents;

 void
Invoke()
 {

  //触发OnBeforeInvoke事件
  if (m_pEvents != NULL)
   m_pEvents->OnBeforeInvoke();
 
  cout<<"CSomeObject2::Invoke()"<
 
  //触发OnAfterInvoke事件
  if (m_pEvents != NULL)
   m_pEvents->OnAfterInvoke
();
 }
};

//CSomeObject2对象的创建者类
class CEventTest2 : public ISomeObject2Events
{

 CSomeObject2 m_objSome;
 //调用前事件处理
virtual void OnBeforeInvoke()
 {

  cout<< "调用前..." < };

 //调用后事件处理
virtual void OnAfterInvoke()
 {

  cout << "调用后..." < };

 //安装事件
void InstallEvents()
 {

  m_objSome.m_pEvents = this
;
 }

 //卸载事件
void UninstallEvents()
 {

  m_objSome.m_pEvents = NULL
;
 }

public:
 CEventTest2
()
 {

  InstallEvents
();
 }
 
 ~
CEventTest2
()
 {

  UninstallEvents
();
 }

 void Invoke()
 {

  m_objSome.Invoke
();
 }

};

int main(int argc, char* argv[])
{

 CEventTest2 test2;
 test2.Invoke
();
}


这两种方式各有利弊,使用函数指针的好处是触发事件效率高。而采用虚函数的形式的好处是代码更令活更清晰一些。大家可以凭喜好来选择。如果大家看过之后有什么指教或补充,请千万别吝惜你的思想和文字。
       
本质上,Delphi,C#都是采用函数指针的机制来处理事件的.即将函数指针作为类的一个成员,在某个事件发生时,来调用相应的函数.但在Delphi,C#这样的语言中,事件的处理函数是匿名的,即,一个对象并不知道预订了自己某个事件的函数属于什么类,等等.只是在事件触发时,调用这些方法而已.我也曾经尝试在C++中实现类似的效果,但因为C++本身的语言特性所决定,在C++在要实现这样的机制是很困难的.就像上例中,"事件"只能指向全局函数.成员指针可以指向成员函数,可是成员指针要求你在赋值之前,就要告诉编译器,要指向一个什么类的方法. 这从本质上就限制了在C++中使用"事件"特性.BCB中实现了这样的特性,但这是在编译层做了大量的工作,才实现的.C++语言本身并没有包含这样的特性.其实我很欣赏Delphi中的这种机制,优点很多,比MFC中的什么消息映射不知要好多少倍.


 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值