• boost------signals2的使用2(Boost程序库完全开发指南)读书笔记


    1、应用于观察者模式

    本小节将使用signals2开发一个完整的观察者模式示例程序,用来演示信号/插槽的用法。这个程序将模拟一个日常生活场景:客人按门铃,门铃响,护士开门,婴儿哭闹。


    Ring.h

    #ifndef __RING_H__
    #define __RING_H__
    
    #include "iostream"
    using namespace std;
    #include "boost/signals2.hpp"
    
    
    class Ring
    {
    public:
    	typedef boost::signals2::signal<void()> signal_t;
    	typedef signal_t::slot_type slot_t;
    
    	boost::signals2::connection connect(const slot_t& s)
    	{
    		return alarm.connect(s);
    	}
    
    	void Press()
    	{
    		cout << "Ring alarm..." << endl;
    		alarm();
    	}
    
    private:
    	signal_t alarm;
    };
    
    
    #endif // !__RING_H__
    


    Nurse.h

    #ifndef __NURSE_H__
    #define __NURSE_H__
    
    
    #include "boost/random.hpp"
    
    
    extern char const nurse1[] = "Mary";
    extern char const nurse2[] = "Kate";
    
    typedef boost::variate_generator<boost::rand48, boost::uniform_smallint<> > bool_rand;
    bool_rand g_rand(boost::rand48(time(0)), boost::uniform_smallint<>(0, 100));
    
    template<char const* name>
    class Nurse
    {
    public:
    	Nurse() : rand_(g_rand) { }
    
    	void Action()
    	{
    		cout << name;
    		if (rand_() > 30)
    		{
    			cout << " wake up and open door." << endl;
    		}
    		else
    		{
    			cout << " is sleeping..." << endl;
    		}
    	}
    
    private:
    	bool_rand& rand_;
    };
    
    
    #endif // !__NURSE_H__



    Baby.h

    #ifndef __BABY_H__
    #define __BABY_H__
    
    
    extern char const baby1[] = "Tom";
    extern char const baby2[] = "Jerry";
    
    template<char const* name>
    class Baby
    {
    public:
    	Baby() : rand(g_rand) { }
    	void Action()
    	{
    		cout << "Baby " << name;
    		if (rand() > 50)
    		{
    			cout << " wake up and crying loudly..." << endl;
    		}
    		else
    		{
    			cout << " is sleeping sweetly..." << endl;
    		}
    	}
    
    private:
    	bool_rand& rand;
    };
    
    
    #endif // !__BABY_H__
    


    Guest.h

    #ifndef __GUEST_H__
    #define __GUEST_H__
    
    #include "Ring.h"
    
    class Guest
    {
    public:
    	void Press(Ring& r)
    	{
    		cout << "A guest press the ring." << endl;
    		r.Press();
    	}
    };
    
    
    #endif // !__GUEST_H__
    


    main

    #include "stdafx.h"
    #include "boost/utility/result_of.hpp"
    #include "boost/typeof/typeof.hpp"
    #include "boost/assign.hpp"
    #include "boost/ref.hpp"
    #include "boost/bind.hpp"
    #include "boost/function.hpp"
    #include "boost/signals2.hpp"
    #include "numeric"
    #include "iostream"
    using namespace std;
    #include "Ring.h"
    #include "nurse.h"
    #include "Baby.h"
    #include "Guest.h"
    
    
    int _tmain(int argc, _TCHAR* argv[])
    {
    	// 声明门铃、护士、婴儿、客人等类的实例
    	Ring r;
    	Nurse<nurse1> n1;
    	Nurse<nurse2> n2;
    	Baby<baby1> b1;
    	Baby<baby2> b2;
    	Guest g;
    
    	// 把护士、婴儿、门铃连接起来
    	r.connect(boost::bind(&Nurse<nurse1>::Action, n1));
    	r.connect(boost::bind(&Nurse<nurse2>::Action, n2));
    	r.connect(boost::bind(&Baby<baby1>::Action, b1));
    	r.connect(boost::bind(&Baby<baby2>::Action, b2));
    
    	// 客人按动门铃,触发一系列的事件
    	g.Press(r);
    
    	return 0;
    }
    


    在程序中采用随机数来让护士和婴儿的行为具有不确定性。随机数的产生使用random库,为了方便使用把随机数发生器定义为全局变量:

    typedef boost::variate_generator<boost::rand48, boost::uniform_smallint<> > bool_rand;
    bool_rand g_rand(boost::rand48(time(0)), boost::uniform_smallint<>(0, 100));
    



    然后我们实现护士类nurse,他有一个action()函数,根据随机数决定是惊醒开门还是继续睡觉。注意:他的模板参数,使用了charconst*作为护士的名字,因此实例化时字符串必须声明成extern(要不然别的地方找不到这个串)。

    2、与C#的区别

    signals2中的信号/插槽机制原理上类似于c#语言的event/deletegate机制。

    但c#的deletegate的功能要比signals2弱,它要求精确的类型匹配,也没有合并器的概念,只能返回一个结果。

    deletegate使用operator+=来链接event与deletegate,signals2则使用connect()函数。这是因为signals2在设计时认为operator+=并没有带来太多的好处,反而会导致连续使用+=链接、-=等其他语义问题。

    不过我们可以稍微重载一下+=号来实现这种方式:

    #include "stdafx.h"
    #include "boost/utility/result_of.hpp"
    #include "boost/typeof/typeof.hpp"
    #include "boost/assign.hpp"
    #include "boost/ref.hpp"
    #include "boost/bind.hpp"
    #include "boost/function.hpp"
    #include "boost/signals2.hpp"
    #include "numeric"
    #include "iostream"
    using namespace std;
    
    
    template<int N>
    struct Slot
    {
    	void operator()(int x)
    	{
    		cout << "Slot current N is : " << N << endl;
    	}
    };
    
    template<int N>
    bool operator== (const Slot<N>& a, const Slot<N>& b)
    {
    	return true;
    }
    
    
    template<typename Signature>
    class SigEx
    {
    public:
    	typedef boost::signals2::signal<Signature> signal_type;
    	typedef typename signal_type::slot_type slot_type;
    
    	boost::signals2::connection connect(const slot_type& s)
    	{
    		return sig.connect(s);
    	}
    
    	boost::signals2::connection operator+=(const slot_type& s)
    	{
    		return connect(s);
    	}
    
    	typename signal_type::result_type operator()(typename signal_type::template arg<0>::type a0)
    	{
    		return sig(a0);
    	}
    
    private:
    	signal_type sig;
    };
    
    
    int _tmain(int argc, _TCHAR* argv[])
    {
    	SigEx<void(int)> sig;
    
    	sig += Slot<10>();
    	sig += Slot<10>();
    
    	sig(2);
    
    	return 0;
    }
    


    对前几张blog的总结

    首先讨论了result_of库。它很小但功能很强大,使用了模板元编程技术,可以帮助确定一个调用表达式的返回类型,类似typeof库,主要用于泛型编程。


    ref也是一个很小的库。它最初是tuple库的一部分,后来由于其重要性二被移出,成为了单独的库,而且也被收入了TR1标准草案。它能够包装对象的引用,变成一个可以被拷贝、赋值的普通对象,因此减少了昂贵的复制代价,标准库算法、tuple、bind、function等许多库都可以从ref库受益。但ref库实现有个较大的缺陷,不支持operator()重载(函数调用),通过更改源文件,做出了一个示范性质的实现,它可以配合标准库算法和其他库组件正常工作。


    bind是一个功能强大的函数绑定期。它可以绑定任何可调用对象,搭配标准算法可以获得灵活操作容器内元素的强大功能。但bind过于强大也是个弱点。程序员学会bind的用法后往往会倾向于总是用bind解法,而忘记代码的清晰易读才是最重要的。


    function库是函数指针的泛化,可以存储任意可调用的对象,因此function库经常配合bind使用,它可以存储bind表达式的结果,以备之后调用。


    最后是signals2库,它综合运用了前四个组件,使用了信号/插槽机制,是观察者设计模式的一个具体应用,也是一个功能强大的回调框架。使用signals2库可以简化对象间的通信关系,降低它们的耦合性,只需要在程序开始时把它们连接起来,之后的一切都会自动处理。


  • 相关阅读:
    tcpip数据包编码解析(chunk and gzip)_space of Jialy_百度空间
    epoll 事件之 EPOLLRDHUP
    c What is the Difference Between read() and recv() , and Between send() and write()? Stack Overflow
    HTTP KeepAlive详解 IT心雪的日志 网易博客
    北京生活 TIPS 银行服务篇
    eventfdaiotest.c
    北京生活 TIPS 谈谈日常理财
    C语言抓http gzip包并解压 失败 C/C++ ChinaUnix.net
    转:javascript 对象和原型
    转:Javascript原型链和原型的一个误区
  • 原文地址:https://www.cnblogs.com/jiangu66/p/3230928.html
Copyright © 2020-2023  润新知