通过c++11的std::bind及std::function实现类方法回调,模拟Qt实现信号槽
2023-09-14 09:07:02 时间
c++11引入了std::bind及std::function,实现了函数的存储和绑定,即先将可调用的对象保存起来,在需要的时候再调用。网上有很多介绍。
Qt信号槽实现信号的发送和接收,类似观察者。简单说明:
sender:发出信号的对象
signal:发送对象发出的信号
receiver:接收信号的对象
slot:接收对象在接收到信号之后所需要调用的函数(槽函数)
emit:发送信号
下面实现第一种:
#include <functional>
#include <iostream>
class SignalObject
{
public:
void connect(std::function<void(int)> slot)
{
_call = slot;
}
void emitSignal(int signal)
{
_call(signal);
}
private:
std::function<void(int)> _call;
};
class SlotObject
{
public:
SlotObject(){}
public:
void slotMember(int signal)
{
std::cout<<"signal:"<<signal<<" recv:"<<this<<std::endl;
}
};
定义了SignalObject信号类和SlotObject槽类,其中信号类中的 std::function<void(int)> _call就是要绑定的槽函数,即回调函数,下面是信号槽绑定:
SignalObject signalObject;
SlotObject slotObject;
std::cout<<"slotObject:"<<&slotObject<<std::endl;
signalObject.connect(std::bind(&SlotObject::slotMember,slotObject,std::placeholders::_1));
signalObject.emitSignal(1);
输出:
slotObject:0x62fe3b
signal:1 recv:0x1040f08
可以发现成功调用了回调函数,并正确接收到了信号,我们的成员函数可以通过回调实现了调用。
但是接收者的地址并不是我们定义的slotobject,即connect的是别的对象,开篇链接介绍知,connect过程发生了拷贝构造。
修改我们的信号类,可以避免拷贝构造
class SignalObject2
{
public:
void connect(SlotObject* recver,std::function<void(SlotObject*,int)> slot)
{
_recver = recver;
_call = slot;
}
void emitSignal(int signal)
{
_call(_recver,signal);
}
private:
SlotObject* _recver;
std::function<void(SlotObject*,int)> _call;
};
即我们在connect时把recv保存起来
SlotObject slotObject;
std::cout<<"slotObject:"<<&slotObject<<std::endl;
SignalObject2 signalObject2;
std::function<void(SlotObject*,int)> slot = &SlotObject::slotMember;
signalObject2.connect(&slotObject,slot);
signalObject2.emitSignal(2);
输出如下:
slotObject:0x62fe3b
signal:2 recv:0x62fe3b
当一个槽slot和多个信号signal连接者,我们并不知道是谁调用的,Qt中我们知道可以通过sender()返回一个QObject*来判断,这里模仿实现sender方法
class Object
{
public:
Object* self()
{
return this;
}
std::function<Object*(void)> _sender;
};
class SlotObject3:public Object
{
public:
SlotObject3(){}
public:
void slotMember(int signal)
{
if(_sender){
std::cout<<"sender:"<<_sender()<<std::endl;
}
std::cout<<"signal:"<<signal<<" recv:"<<this<<std::endl;
}
};
class SignalObject3:public Object
{
public:
void connect(SlotObject3* recver,std::function<void(SlotObject3*,int)> slot)
{
_recver = recver;
_call = slot;
}
void emitSignal(int signal)
{
_recver->_sender = std::bind(&SignalObject3::self,this);
_call(_recver,signal);
_recver->_sender = NULL;
}
private:
SlotObject3* _recver;
std::function<void(SlotObject3*,int)> _call;
};
即定义一个基类Object和一个回调变量sender,在每次发送时绑定上发送者即可
SignalObject3 signalObject3;
SlotObject3 slotObject3;
std::cout<<"signalObject3:"<<&signalObject3<<std::endl;
std::cout<<"slotObject3:"<<&slotObject3<<std::endl;
std::function<void(SlotObject3*,int)> slot3 = &SlotObject3::slotMember;
signalObject3.connect(&slotObject3,slot3);
signalObject3.emitSignal(3);
输出:
signalObject3:0x62fdf0
slotObject3:0x62fde0
sender:0x62fdf0
signal:3 recv:0x62fde0
相关文章
- QT学习笔记:信号与槽(一)
- C++问题-Qt Visual Studio Add-in
- 【C/C++学院】(16)QT版:幸运大抽奖
- atitit.软件开发GUI 布局管理优缺点总结java swing wpf web html c++ qt php asp.net winform
- paip.提升用户体验---c++ qt自定义窗体(2)---边框线的绘制
- paip.c++ qt 外部dll共享库的导入以及引用
- paip.提升用户体验---c++ qt 悬浮窗实现
- C++编写Qt应用程序 如何实现交互效果?
- Qt 纯C++项目发布为dll的方法(超详细步骤)
- Qt QSlider介绍(属性设置、信号、实现滑块移动到鼠标点击位置)
- C++Qt开发——QString(字符串类)
- C/C++ Qt 基本文件读写方法
- C/C++ Qt 常用数据结构
- 使用Qt和C语言或者C++语言实现十、二、八、十六进制之间的转换(两种方法)
- QT+OpenGL 描绘简单图形
- C++Qt开发——HTTP协议
- Qt如何实现界面的阴影效果?
- Qt 事件优先级
- 【C/C++,QT】面试五
- QT项目移植后报错:无法打开包括文件: “ui_xxx.h”
- C++(Qt)与Python混合编程(一)
- C++/Qt:TXT文件读写
- atitit.软件开发GUI 布局管理优缺点总结java swing wpf web html c++ qt php asp.net winform
- Ubuntu20.04下,qt交叉编译报错::15: warning: identifier ‘nullptr‘ is a keyword in C++11 [-Wc++0x-compat]
- Qt学习一门:直接使用QT具