您的位置:逆风者 VC++ 正文
 添加时间:2007-09-01 原文发表:2007-08-31 人气:43 来源:vckbase.com

本文章共5959字,分4页,当前第3页,快速翻页:
 


inline IPrimeEvents::~IPrimeEvents() { }		
有了我的仿函数定义,CPrimeCalculator 是这样触发 Progress 事件的:

// in CPrimeCalculator:

void NotifyProgress(UINT nFound)

{

  for_each(m_clients.begin(), m_clients.end(),

    IPrimeEvents::Progress(nFound));

}		
  到这里,我已经介绍了仿函数类 Progress 和 Done,同时,NotifyProgress 和 NotifyDone 都能用 STL 的 for_each 算法。下一步该做什么?记住,我的目的是完全摆脱 NotifyFoo 函数——或者说得更具体一点,就是把它们实现为模板,以便程序员在创建事件时不必为他们定义的每个事件编写千篇一律的函数。将 for 循环转化为 for_each 算法只是万里长征的第一步。
逆风编程精品
  通过将虚拟成员函数 OnFoo 转换为 Foo 仿函数类型,从而为模板化创造条件。(仿函数在这里有点像 .NET 中的委托。)现在我的通知函数根据类型的不同而不同,替代了函数名,我可以将它们参数化。这样一来,我便可以将整个事件实现移出 CPrimeCalculator ,把它们放入新的模板类 CEventMgr 中,这是一个完全通用的类。如 Figure 3 所示。CEventMgr<I> 保存 I* 指针列表。它具备 Register 和 Unregister 方法以便添加元素和从其列表中删除元素,此外它还有一个模板成员函数 Raise 用于触发事件:

template 

class CEventMgr

{

  ...

  template 

  void Raise(F fn)

  {

    for_each(m_clients.begin(), m_clients.end(), fn);

  }

};

很难相信,平时几乎碰不到的模板套模板的情况?在此处派上用场了。现在触发事件我们可以这样做:
void NotifyProgress(UINT nFound)

{

  m_eventmgr.Raise(IPrimeEvents::Progress(nFound));

}

  没有 for 循环,甚至都没有 for_each,所有细节都被封装在 CEventMgr 之中,事件的触发使用一行代码。我甚至可以完全省略掉 NotifyProgress,每当想要触发事件时仅仅调用 CEventMgr::Raise 即可——然而,好的编码规范促使我宁愿将 Raise 封装在某个函数中,以防万一我要修改 CEventMgr 或将事件触发函数暴露给客户机。既然 NotifyProgress 是内联函数,就不会有幸能丢失。
  如果模板使你伤脑筋,我就再讲清楚一些吧。CEventMgr 是一个参数化的模板类,其参数是事件接口 I。因此 CEventMgr<IPrimeEvents> 根据 IPrimeEvents 实例化一个事件管理器。它保存数据成员 m_clients,该成员是一个 IPrimeEvents 指针列表:list<IPrimeEvents*>。CEventMgr 中是一个模板成员函数:Raise<F>,它将仿函数参数 F 传递给 for_each。所以当你写下面这条语句时:

m_eventmgr.Raise(IPrimeEvents::Progress(nFound));

  编译器明白你试图以 IPrimeEvents::Progress 类型参数调用 CEventMgr::Raise,于是它用模板产生成员函数 CEventMgr::Raise(IPrimeEvents::Progress)。实现代码将仿函数实例传递给 for_each,它为客户机列表中的每个 I* 对象调用仿函数的 operator()。仿函数调用对象的 OnProgress 处理例程——这就是我想要的!模板不是很酷吗?
  我们已经快到终点了。仿函数让我参数化事件方法并使用 for_each,但它们还是太长,我讨厌敲入太多的东西。所以最后一步是引入一些宏来解决这个问题。下面就是 IPrimeEvents 最终的浓缩定义。


class IPrimeEvents {

  DECLARE_EVENTS(IPrimeEvents);

public:

  DEFINE_EVENT1(IPrimeEvents, Progress, UINT /*nFound*/);

  DEFINE_EVENT0(IPrimeEvents, Done);

};

IMPLEMENT_EVENTS(IPrimeEvents);	
  完整的源代码参见 Figure 4 —— 从代码中你可以体会到我竭尽全力进行精简和浓缩。只留下最基本的信息:每个事件处理器的名字和签名。宏假设 Foo 的事件处理器是 OnFoo。一些编程的唯美主义者不喜欢宏,但我不那样。有工具为什么不使用呢?DECLARE_EVENTS 声明构造函数和析构函数;IMPLEMENT_EVENTS 实现内联析构。宏 DEFINE_EVENT0,DEFINE_EVENT1 以及 DEFINE_EVENT2 分别声明和定义了 OnFoo 事件处理器以及不带参数,带一个参数和带两个参数的 Foo 事件仿函数。如果你需要更多的参数,可以定义一个结构,用一个事件参数来传递此结构的指针:
 
本文章更多内容<<上一页 - 1 - 2 - 3 - 4 - 下一页>>
相关文章

用鼠标手势动作来发送命令
在VC中使用 Flash 美化你的程序
更改屏幕显示数据的作弊程序
通过串口收发短消息(上)
C 程序的外部变量与函数
如何用代码动态添加控件
一个关于#include的问题
使用免费界面换肤软件 USkin
把 C# 语言开发的控件内嵌在网页里面
支持数据项查找功能的树控制(CTreeCtrl)类
浅谈PDFlib中文输出(四)PDFlib 接收的几种
后缀表达式求值及校验
用ATL开发复合控件
关于 IDispatch 接口的 LPDispatch 属性的实
获得 Win32 窗口句柄的更好的方法
从 ADO 迁移到 ADO.NET(一)
利用VC++开发ASP图像处理组件(二)
可设置单元格颜色的ClistCtrl类
IP Messenger 详细分析
C :使用 Visual C 2005 的现代语言特色

相关评论


本文章所属分类:首页 VC++

  热门关键字: