随笔 - 32  文章 - 94  trackbacks - 0
<2009年7月>
2829301234
567891011
12131415161718
19202122232425
2627282930311
2345678

常用链接

留言簿(8)

随笔分类

随笔档案

好友连接

搜索

  •  

最新评论

阅读排行榜

评论排行榜

写这个程序前,参考过vczh的VL_Data_Event,也看过何咏的,写的目的:第一主要是想熟练c++的模板;第二是重复发明车轮,也拥有自己的事件类了~~。

上大学开始接触编程,一开始便学习C++,但是教科书对模板的介绍都比较少,当时连比较基础的C++都学得一塌糊涂,更不用说模板了。
现在工作任务完成,有点空闲时间看《C++templates》,看到现在终于能写点像样的C++模板了。

目前事件类的封装还没有对0--5个参数模板的特化,这里只贴出具有6个参数的事件类代码:
  1#pragma once
  2#include <list>
  3using namespace std;
  4
  5//函数调用类抽象接口
  6template<typename param1,typename param2,typename param3,typename param4,typename param5,typename param6>
  7class CY_FunctionInterface
  8{
  9public:
 10    virtual void* GetClassHandler()=0;
 11    virtual void* GetFunHandler()=0;
 12    virtual void Invoke(param1 p1,param2 p2,param3 p3,param4 p4,param5 p5,param6 p6)=0;
 13}
;
 14
 15
 16//全局函数调用类
 17template<typename param1,typename param2,typename param3,typename param4,typename param5,typename param6>
 18class CY_GolobalFunction:public CY_FunctionInterface<param1,param2,param3,param4,param5,param6>
 19{
 20public:
 21    typedef void(*T_HANDLER)(param1 ,param2 ,param3 ,param4 ,param5 ,param6);
 22protected:
 23    union
 24    {
 25        T_HANDLER FuncHandler;
 26        void*   pFPointer;
 27    }
;
 28    
 29public:   
 30    CY_GolobalFunction(T_HANDLER f)
 31    {
 32        FuncHandler=f;
 33    }

 34    void *GetClassHandler()
 35    {
 36        return 0;
 37    }

 38    void *GetFunHandler()
 39    {
 40        return pFPointer;
 41    }

 42    void Invoke(param1 p1,param2 p2,param3 p3,param4 p4,param5 p5,param6 p6)
 43    {
 44        (*FuncHandler)(p1,p2,p3,p4,p5,p6);
 45    }

 46}
;
 47
 48//成员函数调用类
 49template<typename Class,typename param1,typename param2,typename param3,typename param4,typename param5,typename param6>
 50class CY_MemberFunction:public CY_FunctionInterface<param1,param2,param3,param4,param5,param6>
 51{
 52public:
 53    typedef void(Class::*T_HANDLER)(param1,param2,param3,param4,param5,param6);
 54protected:
 55    union
 56    {
 57        T_HANDLER FuncHandler;
 58        void *  pFPointer;
 59    }
;
 60    union
 61    {
 62        Class *OwnClassHandler;
 63        void * pCPointer;
 64    }
;
 65    
 66public:
 67    CY_MemberFunction(Class *pClass,T_HANDLER f)
 68    {
 69        OwnClassHandler=pClass;
 70        FuncHandler=f;
 71    }

 72    void *GetClassHandler()
 73    {
 74        return pCPointer;
 75    }

 76    void *GetFunHandler()
 77    {
 78        return pFPointer;
 79    }

 80    void Invoke(param1 p1,param2 p2,param3 p3,param4 p4,param5 p5,param6 p6)
 81    {
 82        (OwnClassHandler->*FuncHandler)(p1,p2,p3,p4,p5,p6);
 83    }

 84}
;
 85
 86
 87//事件封装
 88template<typename param1,typename param2,typename param3,typename param4,typename param5,typename param6>
 89class CY_Event
 90{
 91protected:
 92    typedef list< CY_FunctionInterface<param1,param2,param3,param4,param5,param6>*> T_FUNCTIONLIST;
 93    typedef typename T_FUNCTIONLIST::iterator T_FUNCTION_ITERATOR;
 94
 95    T_FUNCTIONLIST FunctionList;
 96
 97private:
 98    T_FUNCTION_ITERATOR Find(CY_FunctionInterface<param1,param2,param3,param4,param5,param6>* target)
 99    {
100        void *temp1=target->GetClassHandler();
101        void *temp2=target->GetFunHandler();
102        T_FUNCTION_ITERATOR i=FunctionList.begin();
103        for (;i!=FunctionList.end();i++)
104        {
105            if (temp1==(*i)->GetClassHandler()  &&  temp2==(*i)->GetFunHandler())
106            {
107                break;
108            }

109        }

110        return i;
111    }

112public:
113    inline void Invoke(param1 p1,param2 p2,param3 p3,param4 p4,param5 p5,param6 p6)
114    {
115        T_FUNCTION_ITERATOR i=FunctionList.begin();
116        for (;i!=FunctionList.end();i++)
117        {
118            (*i)->Invoke(p1,p2,p3,p4,p5,p6);
119        }

120    }

121
122    void Bind(typename CY_GolobalFunction<param1,param2,param3,param4,param5,param6>::T_HANDLER gFuncHandle)
123    {
124        CY_GolobalFunction<param1,param2,param3,param4,param5,param6>*addone=new CY_GolobalFunction<param1,param2,param3,param4,param5,param6>(gFuncHandle);
125        if(Find(addone)!=FunctionList.end())//已经存在了,就不需要添加
126            delete addone;//删除临时的new对象
127        else
128            FunctionList.push_back(addone);
129    }

130    void UnBind(typename CY_GolobalFunction<param1,param2,param3,param4,param5,param6>::T_HANDLER gFuncHandle)
131    {
132        CY_GolobalFunction<param1,param2,param3,param4,param5,param6>*delone=new CY_GolobalFunction<param1,param2,param3,param4,param5,param6>(gFuncHandle);
133        T_FUNCTION_ITERATOR delnode=Find(delone);
134        if (delnode!=FunctionList.end())//存在,删除节点和指针
135        {
136            delete (*delnode);
137            FunctionList.erase(delnode);
138        }

139        delete delone;//删除临时的new对象
140    }

141    template<typename Class>
142    void Bind(Class *classHandle,typename CY_MemberFunction<Class,param1,param2,param3,param4,param5,param6>::T_HANDLER mFuncHandle)
143    {
144        CY_MemberFunction<Class,param1,param2,param3,param4,param5,param6>*addone=new CY_MemberFunction<Class,param1,param2,param3,param4,param5,param6>(classHandle,mFuncHandle);
145        if (Find(addone)!=FunctionList.end())//已经存在
146            delete addone;//删除临时的new对象
147        else
148            FunctionList.push_back(addone);
149    }

150    template<typename Class>
151    void UnBind(Class *classHandle,typename CY_MemberFunction<Class,param1,param2,param3,param4,param5,param6>::T_HANDLER mFuncHandle)
152    {
153        CY_MemberFunction<Class,param1,param2,param3,param4,param5,param6>*delone=new CY_MemberFunction<Class,param1,param2,param3,param4,param5,param6>(classHandle,mFuncHandle);
154        T_FUNCTION_ITERATOR delnode=Find(delone);
155        if (delnode!=FunctionList.end())//存在,删除节点和指针
156        {
157            delete (*delnode);
158            FunctionList.erase(delnode);
159        }

160        delete delone;//删除临时的new对象
161    }

162    void operator()(param1 p1,param2 p2,param3 p3,param4 p4,param5 p5,param6 p6)
163    {
164        Invoke(p1,p2,p3,p4,p5,p6);
165    }

166    ~CY_Event()
167    {
168        T_FUNCTION_ITERATOR i=FunctionList.begin();
169        for (;i!=FunctionList.end();i++)
170        {
171            delete (*i);
172        }

173    }

174}
;

测试代码:
 1#define _CRTDBG_MAP_ALLOC  
 2#include<stdlib.h>  
 3
 4#include<crtdbg.h>
 5
 6#include <iostream>
 7#include "Event.h"
 8
 9using namespace std;
10
11class MyClass
12{
13public:
14    void func(int a1,int a2,int a3,int a4,int a5,int a6)
15    {
16        cout<<"class func!!"<<endl;
17        cout<<a1<<endl;
18        cout<<a2<<endl;
19        cout<<a3<<endl;
20        cout<<a4<<endl;
21        cout<<a5<<endl;
22        cout<<a6<<endl;
23        cout<<"class func end-----!!"<<endl;
24    }

25}
;
26void gfunc(int a1,int a2,int a3,int a4,int a5,int a6)
27{
28    cout<<"global func!!"<<endl;
29    cout<<a1<<endl;
30    cout<<a2<<endl;
31    cout<<a3<<endl;
32    cout<<a4<<endl;
33    cout<<a5<<endl;
34    cout<<a6<<endl;
35    cout<<"global func end------!!"<<endl;
36}

37
38int main()
39{
40    MyClass class1;
41
42    CY_Event<int,int,int,int,int,int> *eve;
43
44    eve=new CY_Event<int,int,int,int,int,int>;
45
46    eve->Bind(&gfunc);
47    eve->Bind(&class1,&MyClass::func);
48
49    cout<<"invoking"<<endl;
50    eve->Invoke(1,2,3,4,5,6);
51    eve->UnBind(&class1,&MyClass::func);
52    cout<<"-------------after unBind-------------"<<endl;
53    eve->Invoke(6,5,4,3,2,1);
54
55    delete eve;
56
57    int a;
58    cin>>a;
59
60    _CrtDumpMemoryLeaks(); 
61}
运行结果:

posted on 2009-07-25 14:40 陈昱(CY) 阅读(1899) 评论(6)  编辑 收藏 引用 所属分类: C++

FeedBack:
# re: 实现事件的封装(类似C#的 delegate) 2009-07-25 15:48 99读书人
受益了~~~  回复  更多评论
  
# re: 实现事件的封装(类似C#的 delegate) 2009-07-25 19:35 cyberamoeba
hold a candle to the sun  回复  更多评论
  
# re: 实现事件的封装(类似C#的 delegate) 2009-07-25 19:37 cyberamoeba
Sorry, I made a mistake. My previous comment is wrong.  回复  更多评论
  
# re: 实现事件的封装(类似C#的 delegate) 2009-07-25 21:08 legendlee
这种基于模板的多路委托实现多如牛毛,我也刚写了一个,跟你这个基本差不多。我有几个问题:
1成员函数和全局函数封装进统一模型,这个我也是这么做的,但是我没想出来这样有什么用。

2个人觉得CY_FunctionInterface及其子类应该是除了CY_Event之外都不应该看到的,应该设计成内嵌类。

3你测试过虚函数么?
56 {
57 T_HANDLER FuncHandler;
58 void * pFPointer;
59 };
上面的语法对虚函数能用么?我记得虚函数指针是一个类似于__thunk{...}的结构,具体我也不清楚了。

另外,我觉得类似的实现有两个问题导致其不能成为通用方法:
1对象生存期的问题,那个OwnClassHandler要是被析构了怎么办?要是Event在OwnClassHandler之前被析构了怎么办?我的办法是设计两个基本父类实现析构之前互相通知。但是这样要求所有想把自己的成员函数“委托”给Event的类都要继承自一个父类,但是这显然是个“不情之请”。或许可以通过模板和宏来代替,最好像QT那样,一句Q_OBJECT搞定。

2关键在于eve->Bind(&class1,&MyClass::func)这句,在将对象的成员函数委托给事件的操作中,竟然要知道对象是什么类型,这显然也是个“不情之请”。我觉得要解决这个问题必然涉及到类似于反射的机制,但那又是另一个冗繁的故事了。

以上个人看法,有什么不确切的地方还请指正。
  回复  更多评论
  
# re: 实现事件的封装(类似C#的 delegate) 2009-07-26 14:05 CY
1:由于我要实现的事件机制是可以绑定多个函数的。所以封装后,有了统一的接口,就可以放进容器。如果不想绑定多个函数的话,你说得没错,可以直接一个类模板搞定

2:内嵌没有试过,应该没有问题,只要代码第21行、第53行的类型定义对外可见就行了

3:虚函数刚刚测试过,可行!

另外1:这个问题确实没有注意到。觉得对于C++挺难,回去研究~~
2:C++是静态语言,没有办法,之前看过一高手在C++上实现反射,要把所有类型都预定义才行,现在还不太明白,但可以确定的是,反射的实现,也需要“不情之请”。  回复  更多评论
  
# re: 实现事件的封装(类似C#的 delegate)[未登录] 2009-07-27 10:33 duzhongwei
我上次做了个类似AS 3.0事件机制的

IEventListener
  回复  更多评论
  

只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理