下面说说一下成员函数作回调函数的使用,并使用了观察者模式
怎么说呢,推荐一篇博文,参考
dankye的C++回调机制实现
选取里面的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;
}