在C++ 中使用信号和槽(Signals and Slots)
简介本文介绍sigslot这个库 它是用C实现的具有类型安全线程安全的信号和槽机制的库。它完全使用C语言进行编写只有一个头文件因此避免了在使用的时候进行源码的预编译。sigslot的主页是http://sigslot.sourceforge.net。一个Signal/Slot的例子在传统的C代码中类之间的沟通是必须通过调用彼此的成员方法这也就使得每个类要在定义的时候就要指定调用的成员方法以及其说所属的类进行。例如class Switch { public: virtual void Clicked() 0; }; class Light { public: void ToggleState(); void TurnOn(); void TurnOff(); };在不改变Switch或Light类的情况下,让Switch类的Clicked方法控制Light实例的状态那么我们需要这样做class ToggleSwitch : public Switch { public: ToggleSwitch(Light lp) { m_lp lp; } virtual void Clicked() { m_lp.ToggleState(); } private: Light m_lp; }; Light lp1, lp2; ToggleSwitch tsw1(lp1), tsw2(lp2);虽然它也能够工作但是它并不完美最好的方法就是使用信号和槽 在Switch类中不需要考虑控制的是灯还是风扇在Light类中不需要考虑控制这个灯使用的什么样的开关。下边我们就使用库sigslot进行Switch和Light类的改造。class Switch { public: sigslot::signal0 Clicked; }; class Light : public sigslot::has_slots { public: void ToggleState(); void TurnOn(); void TurnOff(); }; Light lp1, lp2; Switch sw1, sw2;主要改动在Switch类中纯虚函数Clicked(), 被一个类型为sigslot::signal0的成员方法取代。在Lightl类中Light类继承于类sigslot::has_slots.修改之后如果希望让Switch控制Light的状态只需要使用下边的方法将Switch的实例和Light的实例进行连接。sw1.Clicked.connect(lp1, Light::ToggleState()); sw2.Clicked.connect(lp2, Light::ToggleState());如果你想再加两盏灯而且每个灯也都有自己的开完我们也再添加两个开关一个开关可以关闭所有的灯一个可以打开所有的灯我们也只需要进行简单的修改。Light lp3, lp4; Switch sw3, sw4, all_on, all_off; sw3.Clicked.connect(lp3, Light::ToggleState()); sw4.Clicked.connect(lp4, Light::ToggleState()); all_on.Clicked.connect(lp1, Light::TurnOn()); all_on.Clicked.connect(lp2, Light::TurnOn()); all_on.Clicked.connect(lp3, Light::TurnOn()); all_on.Clicked.connect(lp4, Light::TurnOn()); all_off.Clicked.connect(lp1, Light::TurnOff()); all_off.Clicked.connect(lp2, Light::TurnOff()); all_off.Clicked.connect(lp3, Light::TurnOff()); all_off.Clicked.connect(lp4, Light::TurnOff());参数类型Signal和Slots也是可以带一个或多个指定类型的参数。库sigslot是建立在C的templated机制上的所以在signal和solts的声明和调用的时候都会进行完全的类型检查。signal类型的命名规则是signalntype1, type2 n是参数的个数。在下边的这个例子中windows在状态发生变化的时候就会发出一系列的信号在MyControl的实例对象中就可以对这些信号进行处理。class Window { public: enum WindowState { Minimised, Normal, Maximised }; signal1WindowState StateChanged; signal2int, int MovedTo; signal2int, int Resized; }; class MyControl : public Control, public has_slots { public: void OnStateChanged(WindowState ws); void OnMovedTo(int x, int y); void OnResize(int x, int y); }; Window w; MyControl c; w.StateChanged.connect(c, MyControl::OnStateChanged); w.MovedTo.connect(c, MyControl::OnMovedTo); w.Resized.connect(c, MyControl::OnResize);信号signal和槽slot的命名不是关键的主要是singal和slot的参数类型和个数要一致。库的使用发送信号例如信号signal2char *, int ReportError;我们使用如下两种方法来发送这个信号1. ReportError(Something went wrong, ERR_SOMETHING_WRONG); 2. ReportError.emit(Something went wrong, ERR_SOMETHING_WRONG);方法1是在类signal2 中对() 的重载实际调用的还是方法emit()连接信号和槽信号的连接是使用方法类signaln的成员方法connect().方法connect()需要指定两个参数1 指向目标实例的指针2 指向目标实例的成员方法的指针为了让方法connect()能够工作需要目标实例的类是继承于类has_slots.一个信号是可以连接到任意数量的槽上的当信号被发送的时候所以连接到这个信号上的槽都会被调用。槽的调用对信号是无感的所以槽方法的返回值都是void。在现在的实现中槽方法是使用std::list进行存储的这也就意味着当一个信号连接了多个槽的时候槽方法的调用顺序和其被连接的顺序是一致的。在未来的版本中可能会对这个行为进行修改因此我们不能确保槽方法的调用顺序一定会和其被连接的顺序一致。断开信号和槽的连接我们很少会用到断开信号的操作 因为当信号实体或者槽实体被析构的时候信号与槽的连接也就被断开了。但是在需要的时候我们还是可以调用方法signal的成员方法disconnec()来断开连接。例如w.Resized.disconnect(c);断开w的Resized信号和槽方法MyControl::OnResize的连接。槽方法的实现槽方法是具有如下属性的普通成员方法返回类型必须是void携带0到8个任意类型的参数必须继承于has_slots槽方法可以在信号槽机制中被调用也可以作为普通方法被调用。断开信号的所用连接signal的成员方法disconnec_all()可以用来断开与该信号连接的所有槽如:all_on.Clicked.disconnec_all(); all_off.Clicked.disconnec_all();此后开关all_on将不能打开所有灯。断开槽对象中所用连接has_slots的成员方法disconnec_all()可以用来断开与该目标对象连接的所有信号lp3.disconnec_all();此后灯lp3将不受开关控制发送一个槽连接的信号信号会将被忽略不会有错误生成这样可以简化程序的编写。如下所示一个可重用的字符串可视化编辑控件类class StringEdit : public has_slots { public: signal0 OnReturnPressed; signal0 OnTabPressed; signal1char OnKeyPressed; signal1char * OnTextChanged; void SetText(char* text); // Slot void ClearText(); // Slot ... };没有错误发生所以每个信号在发送的时候就不用进行烦人的is_connected检查。信号的线程安全signal提供了三种信号安全模式1 single_threaded单线程没有锁的保护2 multi_threaded_global所有信号共享同一个锁锁的创建消耗小但是锁的粒度大3 multi_threaded_local每个信号都有一个锁锁的创建开销大但是粒度小使用方法如下通过Template的最后一个参数指定。// Single-threaded signal1int, single_threaded Sig1; // Multithreaded Global signal1int, multi_threaded_global Sig2; // Multithreaded Local signal1int, multi_threaded_local Sig3槽的线程安全槽函数中的线程安全需要开发者自己来维护但是signal也提供了两个可用的锁1class MyMultithreadedClass : public has_slotsmulti_threaded_local { public: void Entry1() // Slot { lock(); ... unlock(); } void Entry2() // Slot { lock(); ... unlock(); } };2class MyMultithreadedClass : public has_slotsmulti_threaded_local { public: void Entry1() // Slot { lock_blockmulti_threaded_local lock(this); ... } void Entry2() { lock_blockmulti_threaded_local lock(this); ... } }

相关新闻

区分 AI 插件与 AI 原生人事系统,中大型企业选型三大避坑要点

区分 AI 插件与 AI 原生人事系统,中大型企业选型三大避坑要点

一家做美妆连锁的零售企业,全国 32 家门店,总部加门店合计 340 人。2025 年双十一大促前,HR 团队 3 个人加班到凌晨——不是在招人,而是在核对 32 家门店的排班表、社保基数、绩效数据。Excel 表格开了 17 个,跨表引用…

2026/10/24 20:46:26 阅读更多 →
p093基于大数据的房价数据分析-django+spark+spider21(设计源文件+万字报告+讲解)(支持资料、图片参考_相关定制)_

p093基于大数据的房价数据分析-django+spark+spider21(设计源文件+万字报告+讲解)(支持资料、图片参考_相关定制)_

p093基于大数据的房价数据分析-djangosparkspider21(设计源文件万字报告讲解)(支持资料、图片参考_相关定制)_ python3.7djangosparkspidermysql5.7vue 系统采用python为主体开发语言,爬取了大量的房价数据进行数据清洗、通过pandas清洗后入库…

2026/11/4 16:29:25 阅读更多 →
p087基于Hadoop的电影数据分析及可视化系统_flask+spider21(设计源文件+万字报告+讲解)(支持资料、图片参考_相关定制)_

p087基于Hadoop的电影数据分析及可视化系统_flask+spider21(设计源文件+万字报告+讲解)(支持资料、图片参考_相关定制)_

p087基于Hadoop的电影数据分析及可视化系统_flaskspider21(设计源文件万字报告讲解)(支持资料、图片参考_相关定制)_ python3.7hadoopflaskspidermysql5.7vue

2026/11/3 2:19:16 阅读更多 →

最新新闻

Electron桌面应用开发实战:从环境搭建到打包发布全流程

Electron桌面应用开发实战:从环境搭建到打包发布全流程

做前端这些年,我大部分时间都在跟浏览器标签页打交道,直到第一次把桌面应用跑起来,才发现原来自己一直被限制在地址栏和刷新按钮围起来的框框里。Electron这个词,最开始是在某段时间频繁出现在同事的讨论里,一个用HTML…

2026/11/4 1:35:24 阅读更多 →
滑盖智能锁T109深度解析:结构原理、安装调试与故障排查

滑盖智能锁T109深度解析:结构原理、安装调试与故障排查

简介:亚太天能T109滑盖智能锁产品说明书是一份PDF格式的官方技术文档,主要面向智能锁安装人员、终端用户及售后维护者,帮助快速掌握产品安装、配置与常见故障处理。全包仅1个PDF文件,大小4.37MB,内容结构清晰&#xff…

2026/11/3 10:57:27 阅读更多 →
PMSM弱磁控制原理与Simulink建模:高速AGV驱动系统设计指南

PMSM弱磁控制原理与Simulink建模:高速AGV驱动系统设计指南

上个月我在调试一台高速AGV的驱动系统,整车要求空载跑到8m/s,电机转速已经拉到额定点,驱动器的输出电压也顶到了母线电压极限附近。再往上踩速度指令,转速纹丝不动,三相电流反而开始震荡。那会儿我的第一反应就是&…

2026/11/3 11:35:49 阅读更多 →
C++核心知识点:从内存管理到STL的实战指南

C++核心知识点:从内存管理到STL的实战指南

C 这门语言我前前后后折腾了十几年,用它写过嵌入式驱动、做过游戏服务端,也搭过基础组件库。每次看到新人一头扎进"C 核心知识点"这个搜索词,我其实挺感慨的——这门语言的难点从来不是语法多,而是知识点之间的耦合太深…

2026/11/4 6:23:50 阅读更多 →
T109滑盖智能锁怎么装?安装调试与故障排查全攻略

T109滑盖智能锁怎么装?安装调试与故障排查全攻略

简介:亚太天能T109滑盖智能锁产品说明书以PDF格式发布,适合智能锁用户、安装人员与售后维修人员阅读。内容围绕T109系列指纹密码刷卡锁展开,先介绍前面板、后面板、锁体、机械钥匙、电池盒盖等部件名称与功能,再给出完整安装步骤&…

2026/11/3 10:47:27 阅读更多 →
LLM知识降熵:从信息垄断到理解权下放

LLM知识降熵:从信息垄断到理解权下放

你有没有过这种经历:翻开源码注释、论文摘要或者一份专业报告,每个字都认识,连在一起却像天书。想找人聊聊,身边要么没人懂,要么懂的懒得跟你解释。后来我试着把同一段内容丢给一个大语言模型,几秒钟之后&a…

2026/11/3 10:57:33 阅读更多 →

日新闻

周新闻

月新闻