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

VC++
在类VC的界面实现中加入目录树
软件换肤技术在 BCB 中的实现
利用非模窗口生成MDI介面
报表输出轻松搞定
Windows 中不规则窗体的编程实现
解说Win32的窗口子类化
使用测试优先方法开发用户界面
一个简单的登录对话框的实现
一个简单的日记本程序
从资源中加载皮肤
一个在RichEdit中添加表情图象的类
ActiveSkin 4.3 软件换肤在VC中的实现
一种另类“关于(About)”对话框的动态显示方法
对话框打印预览及打印
关于如何换肤、子类化的解决方案
制作 MSN、QQ 的消息提示窗口
如何对 BCGControlBarPro 进行换肤
定制个性化的对话框窗口类
改变窗口中的光标形状
更新MFC中的视图,跟踪.NET Framework中的事件

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


出处:互联网   整理: 软晨网(RuanChen.com)   发布: 2009-10-30   浏览: 50 ::
收藏到网摘: 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统一管理函数指针。回调函数要特别注意函数指针是否为空的问题,因此最好外面在包装一层判断过程。回调函数最大问题在于类型不安全,显式指针这东西……不说也罢……翻了一下智能指针和模版,我发现了一根稻草……