代码改变世界

用C++模拟C#的event机制

2005-11-29 20:51  Orin  阅读(1009)  评论(5编辑  收藏  举报

本文章为farproc.com站长袁晓辉(海洋)的原创文章,作者保留所有权利。如果转载,请务必注明来自www.farproc.com

由于C++不支持event关键字,我们就必须自己写代码。在这里我通过模板类的手段来实现,因为该手段实现的效果和C#比较类似。

在VC6中新建一个win32 console app,命名为“cppevent“。新建一个.h头文件,命名为“event.h”,代码如下:

 1//event.h
 2template <typename Handler>
 3class event
 4{
 5private:
 6    Handler m_Handler;
 7protected:
 8    //模拟C# event 的add/remove访问器
 9    //如果要重新实现add/remove请在派生类中重写这两个函数
10    virtual void add(const Handler value){m_Handler = value;};
11    virtual void remove(const Handler value){if(value == m_Handler)m_Handler = NULL;};
12public:
13    //构造函数
14    event():m_Handler(NULL){}
15    //+= 操作符
16    event& operator += (const Handler value)
17    {
18        add(value);
19        return *this;
20    }

21    //-=操作符
22    event& operator -= (const Handler value)
23    {
24        remove(value);
25        return *this;
26    }

27    //PFN_EVENT_HANDLE 操作符
28    operator Handler()
29    {
30        return m_Handler;
31    }

32}
;

为了能够在定义是指定事件处理函数的原型,我使用了template,为了能和C#一样用+=和-=来定制和撤消事件,我重载了这两个操作符(C#不支持操作符重载),为了能像C#一样直接把event当做函数调用,我有重载了Handler自定义转换操作符,可惜的是,这一点模拟得不是很像,在调用时还必须来一次强制转换才可以:(,具体参看后面的代码:

C++版的MyClass如下:

 1//MyClass.h
 2#include "event.h"
 3//定义EventHandler的函数指针类型
 4typedef void(*EventHandler)(); 
 5
 6class MyClass
 7{
 8public:
 9    //构造函数
10    MyClass(){};
11    //声明一个事件
12    event<EventHandler> AEvent;
13    //激发事件
14    void FireEvent()
15    {
16        if(AEvent != NULL) 
17        {
18            //C++中必须用EventHandler进行强制类型转换
19            ((EventHandler)AEvent)();
20        }
;
21     }

22}
;


和C#版的MyClass比较一下你就会发现代码非常接近,当然,C#是在语言级直接支持event关键字的,而C++不支持,用模板类代替,所以声明事件的代码有些不一样。还有就是FireEvent()中C++不能把event对象直接当做函数来调用,多了强制类型转换。

C++版的客户代码如下:

 1// cppevent.cpp : Defines the entry point for the console application.
 2//
 3
 4#include "stdafx.h"
 5#include "MyClass.h"
 6
 7//向前声明
 8void MyEventHandler(); 
 9
10int main(int argc, char* argv[])
11{
12    MyClass Obj;
13    Obj.AEvent += MyEventHandler;//定制事件
14    Obj.FireEvent();//这行将导致MyEventHandler被调用
15    Obj.AEvent -= MyEventHandler;//撤消事件
16    Obj.FireEvent();//这个将不会引发事件
17
18    printf("结束!\n");
19    char n;
20    scanf("%c"&n);
21    return 0;
22}

23
24void MyEventHandler()
25{
26    printf("This is a event!\n");
27}


我们可以看到,可C#版的客户代码相比,核心部分是非常接近的,我们已经可以和C#一样用“+=”和“-=”来定制事件和撤消事件定制,并在Obj的FireEvent()被调用时收到事件通知,输出文本。

鉴于篇幅的原因,我们没有仔细比较两个版本的event的add和remove访问器/成员函数,其实二者也是非常类似的,你可以自己试试。C++版的event的add和remove均为virtual的,你可以从event类继承出来一个MyEvent类,然后重新实现这两个函数,就可以定制自己的add和remove了。这和C#的add/remove访问器的也是非常相像的。

 

三、总结

通过这场“模仿show”我们可以从更深的层次理解C#的event机制,更重要的是我们用自己所熟悉的东西(C++,模板类)来模仿并解释了我们目前还不太熟悉的东西(C#,event)。

其实,C#的delegate就是C++的函数指针,C# event的核心机制就是C++中的模板(定义event时表现出来)和运算符重载(+=、-=和直接把event当做函数调用)的结合体。C#把C++中容易出错的部分用“新特性”封装了起来,把这部分工作从programmer身上转移到了compiler身上,让我们把更多的精力集中到业务逻辑的处理上。