zoukankan      html  css  js  c++  java
  • C++ 观察者模式二-----成员函数作回调

    下面说说一下成员函数作回调函数的使用,并使用了观察者模式

    怎么说呢,推荐一篇博文,参考

    dankyeC++回调机制实现 

    选取里面的signal—slot(信号与槽)来说,QT实现了信号与槽的整套机制,有兴趣的朋友可以去查看下源码信息

    任何对象的槽可以绑定到一个对象的信号上,一个信号可以拥有多个槽。

    介绍下将要登场的一些成员: slot类,类似一个连接器,将receiver 绑定到 signal上去,这样 sender就可以发signal,signal就会执行响应的slot里面的方法,slot直接调用绑定到slot里面的reciver

    一个简单的signal/slot实现

    template <typename T, typename T1>
    class slot
    {
    public:
    	slot(T *pObj, void (T::*pMemberFunc)(T1))
    	{
    		m_pObj = pObj;
    		m_pMemberFunc = pMemberFunc;
    	}
    	void Execute(T1 para)
    	{
    		(m_pObj->*m_pMemberFunc)(para);
    	}
    private:
    	T * m_pObj;
    	void (T::*m_pMemberFunc)(T1 para);
    };
    template<typename T, typename T1>
    class signal
    {
    public:
    	void bind(T* pObj, void (T::*pMemberFunc)(T1))
    	{
    		m_slots.push_back(new slot<T, T1>(pObj, pMemberFunc));
    	}
    	~signal()
    	{
    		vector<slot<T,T1> *>::iterator ite = m_slots.begin();
    		while (ite != m_slots.end())
    		{
    			delete *ite;
    			ite++;
    		}
    	}
    	void operator()(T1 para)//重载操作符()
    	{
    		vector<slot<T,T1> *>::iterator ite = m_slots.begin();
    		while (ite != m_slots.end()) {
    			(*ite)->Execute(para);
    			ite++;
    		}
    	}
    private:
    	vector<slot<T,T1> *>m_slots;
    };
    
    class receiver
    {
    public:
    	void callback1(int a)
    	{
    		cout << "receiver1:" << a << endl;
    	}
    	void callback2(int a)
    	{
    		cout << "receiver2:" << a << endl;
    	}
    };
    
    //构造sender类产生signal信号
    class sender
    {
    public:
    	sender(int value) :m_value(value) {}
    	~sender() {}
    	int get_value()
    	{
    		return m_value;
    	}
    	void set_value(int new_value)
    	{
    		if (new_value != m_value)
    		{
    			m_value = new_value;
    			m_sig(new_value);
    		}
    
    
    	}
    	signal<receiver, int> m_sig;
    private:
    	int m_value;
    };
    
    int main()
    {
    	receiver r;
    	sender s(5);
    	s.m_sig.bind(&r, &receiver::callback1);
    
    	s.m_sig.bind(&r, &receiver::callback2);
    	s.set_value(6);
    	return 0;
    }
    
    

    简述:上面的对应关系很简单 将sender 发送signal信号 receiver 定义自己的callback 通过 slot将信号与 receiver对应起来。
    因为成员函数在类外不可直接调用,必须使用对象来进行调用,所以引如了一个对象,来对回调函数进行调用。
    首先将receiver 通过 slot 绑定到 signal上。然后sender发送一个signal ,执行调用。相当于信号触发,来执行signal里绑定的槽的方法。
    总体的思路挺清晰的。
    上面的参数模板T,T1 T代表receiver类,T1代表int类型参数,
    问题:
      sender类在实例化signal的时候必须提供两个模板参数,可是调用方哪会事先就知道receiver接收方的类型 呢,而且从概念上讲,事件发送方与接收方只需遵循一个共同的接口函数接口就可以了,与类没什么关系,
    上个程序要求在实例化时就得填充receiver的类型,  也就决定了receiver只能一对一,而不能一对多,于是作出改进,将signal的参数T去掉,将T类型的推导延迟到绑定(bind)时,signal没有参数T,slot也就不能有,
    可是参数T总得找个地方落脚啊,怎么办?让slot包含slotbase成员,slotbase没有参数T的,但slotbase只定义接口,真正的实现放到slotimpl中,slotimpl就可以挂上参数了,boost中any,share_ptr就是用此手法,

    
    
    #include <vector>
    #include <iostream>
    using namespace std;
    /*
    
    version:2.0
    */
    
    #include <vector>
    #include <iostream>
    using namespace std;
    template<typename T1>
    class slotbase
    {
    public:
    	virtual void Execute(T1 para) = 0;//定义虚函数 作接口用
    };
    template<typename T,typename T1>
    class slotimpl :public slotbase<T1>
    {
    public:
    	slotimpl(T* pObj, void (T::*pMemberFunc)(T1 para))
    	{
    		m_pObj = pObj;
    		m_pMemberFunc = pMemberFunc;
    	}
    	virtual void Execute(T1 para)
    	{
    		(m_pObj->*m_pMemberFunc)(para);
    	}
    private:
    	T* m_pObj;
    	void (T::*m_pMemberFunc)(T1 para);
    };
    
    
    template <typename T1>
    class slot
    {
    public:
    	template<typename T>
    	slot(T*Obj, void (T::*pMemberFunc)(T1 para))
    	{
    		m_Slotbase = new slotimpl<T, T1>(Obj, pMemberFunc);
    	}
    	~slot()
    	{
    		delete m_Slotbase;
    	}
    	void Execute(T1 para)
    	{
    		m_Slotbase->Execute(para);
    	}
    private:
    	slotbase<T1> *m_Slotbase;
    
    
    };
    
    template <typename T1>
    class signal
    {
    public:
    	template <typename T>
    	void bind(T* pObj, void(T::*pMemberFunc)(T1 para))
    	{
    		m_slots.push_back(new slot<T1>(pObj, pMemberFunc));
    	}
    	~signal()
    	{
    		vector<slot<T1>*>::iterator ite = m_slots.begin();
    		for (; ite != m_slots.end(); ite++)
    		{
    			delete *ite;
    		}
    	}
    	void operator()(T1 para)
    	{
    		vector<slot<T1>*>::iterator ite = m_slots.begin();
    		//for (; ite != m_slots.end(); ite++)
    		//{
    		//	(*ite)->Execute(para);
    		//}
    		while (ite != m_slots.end())
    		{
    			(*ite)->Execute(para);
    			ite++;
    		}
    	}
    
    private:
    	vector<slot<T1>*> m_slots;
    };
    
    #define CONNECT(sender,signal,receiver,slot)  sender.signal.bind(receiver,slot)
    
    class receiver
    {
    public:
    	void callback1(int a )
    	{
    		cout << "receiver1: " << a << endl;
    
    	}
    
    };
    class receiver2
    {
    public:
    	void callback2(int a)
    	{
    		cout << "receiver2: " << a << endl;
    	}
    };
    class sender
    {
    public:
    	sender() :m_value(0) {};
    	int get_value()
    	{
    		return m_value;
    	}
    
    	void set_value(int new_value)
    	{
    		if (new_value != m_value)
    		{
    			m_value = new_value;
    			m_valueChanged(m_value);
    		}
    	}
    	signal<int>m_valueChanged;
    private:
    	int m_value;
    };
    
    int main()
    {
    	receiver r;
    	receiver2 r2;
    	sender s;
    	CONNECT(s, m_valueChanged, &r, &receiver::callback1);
    	CONNECT(s, m_valueChanged,&r2,&receiver2::callback2);
    
    	s.set_value(1);
    	return 0;
    }
    

      

     

    
    
  • 相关阅读:
    STL_算法_查找算法(lower_bound、upper_bound、equal_range)
    Kafka深度解析
    hdoj 1027 Ignatius and the Princess II 【逆康托展开】
    代码二次封装-xUtils(android)
    C++11新特性应用--介绍几个新增的便利算法(用于排序的几个算法)
    谨防串行的状态报告会
    hadoop中NameNode、DataNode和Client三者之间协作关系及通信方式介绍
    Kindeditor JS 取值问题以及上传图片后回调等
    MySQL 8.0.11 报错[ERROR] [MY-011087] Different lower_case_table_names settings for server ('1')
    爱的链条
  • 原文地址:https://www.cnblogs.com/lobsterIT/p/5606744.html
Copyright © 2011-2022 走看看