POCO C++库学习和分析 -- 通知和事件 (四)
5. 事件
Poco中的事件和代理概念来自于C#。对于事件的使用者,也就是调用方来说,用法非常的简单。
5.1 从例子说起
首先让我们来看一个同步事件例子,然后再继续我们的讨论:
[cpp]
1. #include \ 2. #include \ 3. #include
5. using Poco::BasicEvent; 6. using Poco::Delegate; 7.
8. class Source 9. { 10. public:
11. BasicEvent
14. theEvent(this, n);
15. // theEvent.notify(this, n); // alternative syntax 16. } 17. }; 18.
19. class Target 20. { 21. public:
22. void onEvent(const void* pSender, int& arg) 23. {
24. std::cout << \ << arg << std::endl; 25. } 26. }; 27.
28. int main(int argc, char** argv) 29. {
30. Source source; 31. Target target;
32. source.theEvent += Poco::delegate(&target, &Target::onEvent); 33. source.fireEvent(42);
34. source.theEvent -= Poco::delegate(&target, &Target::onEvent);
1
35.
36. return 0; 37. }
从上面的代码里,我们可以清晰的看到几个部分,数据源Source,事件BasicEvent
[cpp]
1. void fireEvent(int n) 2. {
3. theEvent(this, n);
4. // theEvent.notify(this, n); // alternative syntax 5. }
theEvent(this, n)中存在两个参数,其中n为Target::onEvent(const void* pSender, int& arg)处理函数的参数,可理解为消息或者事件内容;this给出了触发源实例的信息。
ok。这样消息的传递流程出来了。消息源实例的地址,消息内容,目标实例地址,目标实例类的处理函数入口地址。使用者填入上述信息就可以传递消息了。相当简单。
而对于事件的开发者,如何实现上述功能。这是另外一码事,用C++实现这么一个功能还是挺复杂的一件事。看一下使用语言的方式,想一下用到的C++技术: 1. +=/-= 重载
[cpp]
1. source.theEvent += Poco::delegate(&target, &Target::onEvent);
2. 仿函式
[cpp]
1. theEvent(this, n);
3. 模板
开发者是不应该限定使用者发送消息的类以及接受消息类的类型的,因此C++中能够完成此功能的技术只有模板了。关于模板编程还想聊上几句。STL的特点在于算法和数据结构的分离,这个其实也是泛型编程的特点。如果把使用者对于类的应用过程看做算法过程的话,就可以对这个过程进行泛型编程。同时应该注意的是,算法和数据结构是存在关联的,这是隐含在泛型编程中的,能够使用某种算法的数据结构一定是符合该种算法要求的。
就拿Poco中事件的委托Delegate来说,目标对象处理事件的函数入口是存在某种假设的。Poco中假设入口函数必须是如下形式之一:
[cpp]
1. void (TObj::*NotifyMethod)(const void*, TArgs&);
2
2. void (TObj::*NotifyMethod)(TArgs&); 3. void (*NotifyMethod)(const void*, TArgs&); 4. void (*NotifyMethod)(void*, TArgs&);
5.2 事件的实现
下面一张图是Poco中Event的类图:
下面另一张图是Poco中Event流动的过程:
3