事件编程(二),事件编程(二)
【 tulaoshi.com - C语言心得技巧 】
C++ At Work 专栏...
事件编程(二)
原著:Paul DiLascia
翻译:NorthTibet
下载源代码:CAtWork0603.exe (3,178KB)
原文出处:Event Programming, Part 2
在本文的第一部分(事件编程一),我回答了一个关于用 C++ 实现本机事件的问题。讨论了一般意义上的事件并示范了如何用接口为你的类定义事件处理器,事件的处理必须在客户机实现。我的实现有一些缺陷,我承诺过最终要解决掉,本文就来完成这件事情。
在开始之前,先简单回顾一下前面写的那个程序,PrimeCalc。如 Figure 1 所示:
Figure 1 计算素数
程序中使用了一个计算素数的类 CPrimeCalculator,这个类发起两个事件:Progress 和 Done。当搜索到素数时,该类触发 Progress 事件以报告目前发现了多少素数。完成处理后触发 Done 事件。这两个事件都是由接口 IPrimeEvents 定义的:
class IPrimeEvents {public: virtual void OnProgress(UINT nPrimes) = 0; virtual void OnDone() = 0;};客户机要想处理事件必须得从 IPrimeEvents 派生,实现事件处理函数,并调用 CPrimeCalculator::Register 来注册其接口。CPrimeCalculator::Register 会将客户机对象/接口添加到其内部列表。当触发了一个 Progress 事件时,CPrimeCalculator 便调用辅助函数 NotifyProgress:
void CPrimeCalculator::NotifyProgress(UINT nFound){ listNotifyProgress 遍历客户机列表,调用每个客户机的 OnProgress 处理函数。当某个程序员使用 CPrimeCalculator 时,编写事件处理代码很容易——只要从 IPrimeEvents 派生并实现处理器即可。但是在实现这种触发事件的 CPrimeCalculator 类机制时冗长乏味。你必须得为每个事件(如 Foo)实现诸如 NotifyFoo 这样的函数,即使处理模式一模一样。事件触发代码被划分在两个类中,事件接口 IPrimeEvents 和 事件源 CPrimeCalculator。如果你想将同样的事件接口用于不同的事件源那该怎么办?IPrimeEvents 是很通用,我可能将它改名为 IProgressEvents 并将它用于任何以整数形式报告处理进度的类并在完成处理时用 Done。但每个触发 Progess 事件的类必须重新实现触发事件的通知函数。理想情况下,所有事件代码都应该放在单个类中。::iterator it; for (it=m_clients.begin(); it!=m_clients.end(); it++) { (*it)->OnProgress(nFound); }}
// NotifyFoo — raise Foo eventlist<IPrimeEvents*::iterator it;for (it=m_clients.begin(); it!=m_clients.end(); it++) { (*it)-OnFoo(/*args*/);}也就是说迭代客户机列表,并针对每个客户机调用 OnFoo,传递事件参数。如何把它写成一个模板呢?可以将接口 IPrimeEvents 参数化为一个类型 T,但如何参数化事件处理函数 OnFoo,程序员可能选择的任何名字和签名。
for_each(m_clients.begin(), m_clients.end(),NotifyProgress(nFound));
for_each 算法从头到尾迭代容器元素,并对每个元素调用函数对象 NotifyProgress。这里说的“函数对象”到底是指的什么呢?不是一个函数,它是一个对象。这个类看起来像下面这个样子:
class NotifyProgress {protected: UINT m_nFound;public: NotifyProgress(UINT n) : nFound(n) { } void operator()(IPrimeEvents* obj) { obj->OnProgress(nFound); }};NotifyProgress 实现函数 operator()(IPrimeEvents*),它是 for_each 算法需要的东西。一般来讲,如果你具备一个类型为 T 对象集合,for_each 会需要一个
来源:http://www.tulaoshi.com/n/20160129/1486206.html