刘未鹏C++的罗浮宫(http://blog./pongba)boost库固然是技术的宝库,却更是思想的宝库。mand,observer等模式,却不知该如何写一个支持该模式的类。正如隔靴搔痒,无法深入。DDJ上曾有一篇文章用C++实现类似C#的event机制,不过是个雏形,。上篇:架构篇引入所谓“事件”机制,简而言之,就是用户将自己的一个或多个回调函数挂钩到某个“事件”上,一旦“事件”被触发,所有挂钩的函数都被调用。毫无疑问,事件机制是个十分有用且常用的机制,不然C#也不会将它在语言层面实现了。但是C++语言并无此种机制。幸运的是boost库的开发者们替我们做好了这件事(事实上,他们做的还要更多些)。他们的类称作signal,即“信号”的意思,当“信号”发出的时候,所有注册过的函数都将受到调用。这与“事件”本质上完全一样。简单情况下,你只需要这样写:doublesquare(doubled){returnpi*r*r;}//面积doublecircle(doubled){return2*pi*r;}//周长//double(double)是一个函数类型,意即:接受一个double型参数,返回double。signal<double(double)double(double)是个类型,函数类型。所谓函数类型可以看作将函数指针类型中的’(*)’去掉后得到的类型。事实上,函数类型在面临拷贝语义的上下文中会退化为函数指针类型。>sig;(&square);//(&circle);//注册circle//触发该信号,sig会自动调用square(),circle(),并返回最后一个函数,circle()的返回值doublec=sig();//assert(c==circle())signal能够维护一系列的回调函数,并且,signal还允许用户指定函数的调用顺序,signal还允许用户定制其返回策略,默认情况下返回(与它挂钩的)最后一个函数的返回值,当然你可以指定你自己的“返回策略”(比如:返回其中的最大值),其中手法,甚为精巧。另外,如果注册的是函数对象(仿函数)而非普通函数,则signal还提供了跟踪能力,即该函数对象一旦析构,则连接自动断开,其实现更是精妙无比。俗语云:“熟读唐诗三百首,不会吟诗也会吟”。写程序更是如此。如果仔细体会,会发现signal的实现里面隐藏了许许多多有价值的思想和模式。何况boost库是个集泛型技术之大成的库,其源代码本身就是一笔财富,对于深入学习C++泛型技术是极好的教材。所以本文不讲应用,只讲实现,。。。另外,本文尽量少罗列代码,多分析架构和思想,并且列出的代码为了简洁起见,往往稍作简化boost库的源代码里面宏和泛型用得极多,的确很难读懂,所以本文中列出的代码都是简单起见,只取出其中最关键的部分。所有的宏都已展开,所以,有些代码与boost库里的源代码有些不同。,略去了一些细节,但是都注明其源文件,自行参照。在继续往下读之前,建议大家先看看boost库的官方文档,了解signal的各种使用情况,这样,在经历下面繁复的分析过程时心中才会始终有一个清晰的脉络。事实上,我在阅读代码之前也是从各种例子入手的。架构Signal的内部架构,如果给出它的总体轮廓,非常清晰明了。见下图:图一显然,signal在内部需要一个管理设施来管理用户所注册的函数(这就是图中的slotmanager),从根本上来说,boost::signal中的这个slot“管理器”就是multimap(如果你不熟悉multimap,可以参考一些STL方面的书籍(如《C++STL》《泛型编程与STL》)或干脆查询MSDN。这里我只简单的说一下——multimap将键(key)映射(map)到键值(键和键值的类型可以是任意),就像字典将字母映射到页码一样。)它负责保存所谓的slot,每一个slot其实本质上是一个boost::functionboost::function是个泛型的函数指针类,例如boost::function<int(int,double)>可以指向任何类型为int(int,double)的函数或仿函数。函数对象,该函数对象封装了用户注册给signal回调的函数(或仿函数)。当然,slot是经过某种规则排序的。这正是signal能够控制函数调用顺序的原因。当你触发signal时,其内部迭代遍历“管理器”——multimap,找出其中保存的所有函数或函数对象并逐一调用它们。听起来很简单,是不是
Boost源码剖析之:多重回调机制signal(上) 来自淘豆网m.daumloan.com转载请标明出处.