在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/7/28 19:59:51 阅读更多 →
p093基于大数据的房价数据分析-django+spark+spider21(设计源文件+万字报告+讲解)(支持资料、图片参考_相关定制)_

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

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

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

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

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

2026/7/28 19:58:51 阅读更多 →

最新新闻

FastFlix:高效视频格式转换工具的技术解析与应用

FastFlix:高效视频格式转换工具的技术解析与应用

1. FastFlix:视频格式转换的终极解决方案作为一名长期处理视频内容的创作者,我深知格式转换这个看似简单的需求背后隐藏着多少痛点。不同平台对视频格式的要求各异,原始素材的编码方式五花八门,而传统转换工具要么速度慢如蜗牛&am…

2026/7/28 20:06:02 阅读更多 →
什么影响了你的工资?方差分析告诉你

什么影响了你的工资?方差分析告诉你

看到这个标题,你可能会想影响工资的因素太多了。学历、工作经验、能力、人脉、机会、行业、地域,等等,都会影响工资,怎么确定每个因素影响了多少工资呢?别急,我们一个一个来分析。 方差分析就是研究类别型…

2026/7/28 20:06:02 阅读更多 →
三菱FX3U PLC配方程序开发与优化实践

三菱FX3U PLC配方程序开发与优化实践

1. 项目背景与需求解析去年接手了一个食品包装产线的PLC改造项目,产线需要根据16种不同规格的包装袋自动调整灌装参数。传统做法是在触摸屏上逐个修改参数,不仅效率低下还容易出错。于是决定用三菱FX3U的配方功能实现参数一键切换,这就是今天…

2026/7/28 20:06:02 阅读更多 →
算法日常・每日刷题--<哈希>1

算法日常・每日刷题--<哈希>1

1. 两数之和 - 力扣(LeetCode)1. 两数之和 - 给定一个整数数组 nums 和一个整数目标值 target,请你在该数组中找出 和为目标值 target 的那 两个 整数,并返回它们的数组下标。你可以假设每种输入只会对应一个答案,并且…

2026/7/28 20:06:02 阅读更多 →
TPIC7710 EVM实战:汽车电子驻车制动ASIC评估与开发指南

TPIC7710 EVM实战:汽车电子驻车制动ASIC评估与开发指南

1. 项目概述:从芯片到系统,电子驻车制动ASIC的实战评估在汽车电子设计领域,尤其是关乎行车安全的底盘控制系统,工程师们面临的挑战往往不是“能不能实现”,而是“如何实现得足够可靠、高效且符合严苛的行业标准”。电子…

2026/7/28 20:06:02 阅读更多 →
C#-WPF-控件-CartesianChart图表-线性3(LineSeries)-MVVM模式(封装数据绑定类)

C#-WPF-控件-CartesianChart图表-线性3(LineSeries)-MVVM模式(封装数据绑定类)

知识点:1. 数据绑定(数据绑定类 与 图形操作在同一个类中)2. X轴上显示点数(主类 中) 3. 添加随机值在图表中 (值针对Y轴值)4. 清空图表5. 图标titel显示实例图表控件绑定 SeriesCollectionA&am…

2026/7/28 20:05:01 阅读更多 →

日新闻

告别臃肿!3步让你的暗影精灵笔记本重获新生

告别臃肿!3步让你的暗影精灵笔记本重获新生

告别臃肿!3步让你的暗影精灵笔记本重获新生 【免费下载链接】OmenSuperHub Control Omen laptop performance, fan speeds, and keyboard lighting, and unlock power limits. 项目地址: https://gitcode.com/gh_mirrors/om/OmenSuperHub 你是否也曾为官方Om…

2026/7/28 0:00:43 阅读更多 →
RAG必踩坑!财报法规检索不准?这款开源工具让答案浮出水面,准确率飙升98.7%!

RAG必踩坑!财报法规检索不准?这款开源工具让答案浮出水面,准确率飙升98.7%!

做 RAG 的人应该都踩过这个致命的坑:把几百页的财报、法规、技术手册扔给向量库,问一个具体问题,搜出来的全是沾边但没用的内容 —— 关键信息要么被硬切块拆碎了,要么藏在几十条结果的最下面。语义相似≠真正相关,这个…

2026/7/28 0:00:43 阅读更多 →
抖音视频文案提取工具全指南:免费2026版、手机App、在线工具一网打尽

抖音视频文案提取工具全指南:免费2026版、手机App、在线工具一网打尽

2026年做短视频运营,从抖音上扒文案早就不是偷偷抄笔记的事了。我刚开始做内容的时候,每天刷半小时抖音,手动把爆款视频的口播敲进备忘录,一条2分钟的视频得花十来分钟,碰到语速快的还要反复回听。后来试了一圈工具&am…

2026/7/28 0:00:43 阅读更多 →

周新闻

深度学习道路桥梁裂缝检测系统 道路桥梁裂缝检测数据集 道路桥梁病害识别检测数据集

深度学习道路桥梁裂缝检测系统 道路桥梁裂缝检测数据集 道路桥梁病害识别检测数据集

深度学习道路桥梁裂缝检测系统 数据集6000张 完整源码已标注数据集训练好的模型环境配置教程程序运行说明文档,可以直接使用!系统支持图片、视频、摄像头等多种方式检测裂缝,功能强大实用。 1数据集6000张 8各类别

2026/7/28 12:04:22 阅读更多 →
深度学习YOLO模型如何训练 PUBG 绝地求生目标检测数据集

深度学习YOLO模型如何训练 PUBG 绝地求生目标检测数据集

pubg数据集 精选原图1.42万数据 1.49万标签 无任何重复、算法增强或冗余图像! pubg绝地求生目标检测数据集 1分类:e_body,14905个标签,txt格式 共计14244张图,99%为640*640尺寸图像 适合yolo目标检测、AI训练关键词&am…

2026/7/28 8:29:16 阅读更多 →
Apex英雄目标检测数据集 深度学习框架YOLO如何训练APEX数据集

Apex英雄目标检测数据集 深度学习框架YOLO如何训练APEX数据集

Apex检测数据集数据集详情检测类别: allies enemy tag图片总量:7247张训练集:5139张验证集:1425张测试集:683张标注状态:全部已标注,即拿即用数据格式:支持YOLO格式及其他格式&#…

2026/7/28 5:03:42 阅读更多 →

月新闻