当前位置: 首页 > 图文教程 > 开发语言 > VC++ > 委托、信号和消息反馈的模板实现技术

VC++
用VC++创建自定义向导程序
自定义 CRichEditCtrl 控件
Office 2000 风格的停泊、智能型菜单
黑客攻击手段之偷梁换柱
完善 CPopupText 类
让工具条显示256色图像
定制编辑框的上下文菜单
列表控件排序功能的实现
一个优秀的网格控件CGridCtrl
如何用代码动态添加控件
如何在编辑框中使用IAutoComplete接口
应用程序中添加“Coolbars”的简单方法
介绍一个有Toolbar功能的可重用类 CPopupText
在工具栏按钮上添加文本标签
类似Dreamweaver的颜色选择器
如何设置ListView控件的完全行(Full Row)选项
如何enable/disable菜单项
关于CEdit控件的透明 --作者:monsoon
动态菜单项、状态条提示、工具条提示问题
CAnimateCtrl::Open的使用问题

VC++ 中的 委托、信号和消息反馈的模板实现技术


出处:互联网   整理: 软晨网(RuanChen.com)   发布: 2009-10-30   浏览: 55 ::
收藏到网摘: n/a

委托、信号和消息反馈的模板实现技术
作者:落木随风

提交者:eastvc 发布日期:2003-9-20 10:25:27
原文出处:http://www.cpphelp.net/issue/delegation.html


憋了很长一段时间的想法,在这里说说,希望听听诸位高手的意见。

我写过不少C++程序(当然比起高手还是差远了),写过库也写过客户程序。一般库都会提供一些好用的类供客户程序使用,不少库还可以让客户程序响应库内的某些事件。比如MFC/ATL/VCL提供消息响应,很多ActiveX提供自定义消息响应,甚至是系统底层的中断调用都可以列入这个范畴。然而,正是以上这些“反向”的调用让我觉得很烦恼。

1 继承+多态

乍一看是理所当然的选择,库中的类把响应处理函数设置为虚函数,客户程序可以继承这个类并且重载响应函数。以某个Socket类为例,可以提供一个OnRecv函数用来响应网络数据包到达的处理。客户程序只需要重载OnRecv并进行自己的处理就可以了。

struct Socket { // base class virtual void OnRecv();};
stuct MySocket { // your event-handle class virtual void OnRecv() { /* do sth here ... */ }}

疑问:很多时候这样做实在很烦,特别是做小程序的时候,或者需要快速做原型的时候,一眼望去小小的程序一上来就继承了一大堆东西,颇为不爽。只是想着能省事一点,希望能像那些脚本语言一样快速绑定消息响应,而不是以继承开始工作——我已经害怕看到长长的类继承树了,很多时候根本不必要继承整个类;又或者某些类只提供一个接口而不是具体的类又或者需要多重继承,处理都有一定麻烦;最麻烦的莫过于有时候需要改变响应处理,难道继承好几个下来么——这么多虚表也是浪费啊。

wangtianxing老大点评:为了使用Socket就必须继承Socket,这可以说是Socket的设计的问题。如果需要实现类似的功能的话,可以写成如下,虽然和继承 Socket 没有多少本质的差别,不过确实把消息处理类和Socket的实现扯开了。:

struct SocketEventHandler { virtual void OnRecv() { /* ... */ } virtual void OnSend() { /* ... */ }};
struct Socket { void set_handler( SocketEventHandler* h ) { handler_ = h; } private: SocketEventHandler* handler_;};
struct MyHandler : SocketEventHandler { void OnRecv() { ... }};
Socket s;MyHandler h;s.set_handler( &h );

突然之间,我感到一阵迷茫,非常渴望一种简单明确的表达方法。丢开继承,我们还有什么把戏?我不禁想起了c时代的回调函数……

2 回调函数(CallBack)

非常简单,就是一个函数指针。刚才的OnRecv可以写成这样

struct Socket { void OnRecv() { if(OnRecvHandle!=NULL) OnRecvHandle(); } void (*OnRecvHandle) ();}; 
客户程序只需要编写一个MyOnRecv函数,并且赋值给OnRecvHandle就可以了

void MyOnRecv(); // your event-handle function
Socket foo;
foo.OnRecvHandle = MyOnRecv;

疑问:非常简单,不需要继承类就可以处理,而且随时可以替换不同的处理函数。其实多态的本质也是函数指针,只不过多态是用vtable统一管理函数指针。回调函数要特别注意函数指针是否为空的问题,因此最好外面在包装一层判断过程。回调函数最大问题在于类型不安全,显式指针这东西……不说也罢……翻了一下智能指针和模版,我发现了一根稻草……