C++模拟实现QT信号槽
为了看着更像QT的信号槽,我们也定义一个QObject的父类。
class QObject
{
public:
QObject* self()
{
return this;
}
//获取信号的发送者
std::function<QObject* (void)> _sender;
};
信号的接收者
class Slot :public QObject
{
public:
Slot() {}
public:
//槽函数1
//如需多个参数 可以将void* signal改为void **signal
void slot1(void* signal)
{
//无法使用void*将signal强转为对应类型 使用*(reinterpret_cast<xxx*>(signal));接收
double res = *(reinterpret_cast<double*>(signal));
//signal可以强转为对应类型 直接强转即可
//int res = (int)signal;
if (_sender) {
//获得了信号发送者的实例
/*
do something
*/
}
std::cout << "信号发送的参数 :" << res << " 接收者地址 :" << this << std::endl;
}
//槽函数2
void slot2(void* signal) {
//无法使用void*将signal强转为对应类型 使用*(reinterpret_cast<xxx*>(signal));接收
double res = *(reinterpret_cast<double*>(signal));
//signal可以强转为对应类型 直接强转即可
//int res = (int)signal;
if (_sender) {
//获得了信号发送者的实例
/*
do something
*/
}
std::cout << "信号发送的参数 :" << res << " 接收者地址 :" << this << std::endl;
}
};
信号的发送者
class Signal :public QObject
{
public:
//如需多个参数 可以将void* signal改为void **signal
void emitsignal(void *signal)
{
//向信号的接收者传递实例
_recver->_sender = std::bind(&Signal::self, this);
string tres = __FUNCTION__;
tres += "(";
tres += typeid(signal).name();
tres += ")";
//由于没有实现QT的反射机制,暂且使用函数名及参数类型来获取对应的函数信息 tres值为Signal::emitsignal(void *signal)
for (map<string, vector<function<void(Slot*, void*)>>>::iterator iter = callbacks.begin(); iter != callbacks.end(); iter++) {
//遍历该函数信息对应的所有槽函数进行触发
if (strcmp(iter->first.c_str(), tres.c_str()) == 0) {
for (int i = 0; i < iter->second.size(); i++) {
iter->second[i](_recver, signal);
}
}
}
}
//存储信号和对应的槽函数集合
map<string, vector<function<void(Slot*, void*)>>> callbacks;
Slot* _recver;
};
连接函数Connect
//由于未能实现反射机制,先使用字符串ID来标识具体信号
//如需多个参数 可以将void* signal改为void **signal
void connect(Signal* sender, string signal, Slot* recver, function<void(Slot*, void*)> slot)
{
//接收槽实例
sender->_recver = recver;
//向对应的信号中添加待触发的槽函数
sender->callbacks[signal].push_back(slot);
}
所有代码及测试用例
#include <functional>
#include <iostream>
#include <map>
#include <vector>
using namespace std;
//将参数x强制转换为为void*
#define SIG(x) const_cast<void*>(reinterpret_cast<void*>(x))
class QObject
{
public:
QObject* self()
{
return this;
}
std::function<QObject* (void)> _sender;
};
class Slot :public QObject
{
public:
Slot() {}
public:
void slot1(void* signal)
{
double res = *(reinterpret_cast<double*>(signal));
//int res = (int)signal;
if (_sender) {
}
std::cout << "信号发送的参数 :" << res << " 接收者地址 :" << this << std::endl;
}
void slot2(void* signal) {
double res = *(reinterpret_cast<double*>(signal));
if (_sender) {
}
std::cout << "信号发送的参数 :" << res << " 接收者地址 :" << this << std::endl;
}
};
class Signal :public QObject
{
public:
void emitsignal(void* signal)
{
_recver->_sender = std::bind(&Signal::self, this);
string tres = __FUNCTION__;
tres += "(";
tres += typeid(signal).name();
tres += ")";
for (map<string, vector<function<void(Slot*, void*)>>>::iterator iter = callbacks.begin(); iter != callbacks.end(); iter++) {
if (strcmp(iter->first.c_str(), tres.c_str()) == 0) {
for (int i = 0; i < iter->second.size(); i++) {
iter->second[i](_recver, signal);
}
}
}
}
map<string, vector<function<void(Slot*, void*)>>> callbacks;
Slot* _recver;
};
//连接函数
void connect(Signal* sender, string signal, Slot* recver, function<void(Slot*, void*)> slot)
{
sender->_recver = recver;
sender->callbacks[signal].push_back(slot);
}
int main()
{
Signal signalobject;
Slot slotobject;
connect(&signalobject, "Signal::emitsignal(void *)", &slotobject, &Slot::slot1);
connect(&signalobject, "Signal::emitsignal(void *)", &slotobject, &Slot::slot2);
//信号类型任意 只需与槽函数的参数对应即可
double param = 10.25;
signalobject.emitsignal(SIG(¶m));
//int param =10;
//signalobject.emitsignal(SIG(10));
return 0;
}
结果