什么是信号和槽?纯C++中如何实现信号和槽?

2023-11-08

什么是信号和槽?

在Qt框架中,信号和槽是一种非常灵活的机制,用于在对象之间进行通信。信号和槽可以将两个对象解耦并连接起来,从而使得一个对象发生变化时,另一个对象就能够接收到相应的通知,并执行相关的操作。

例如,在编写一个GUI程序时,我们可以将一个按钮的点击事件定义为一个信号,然后将该信号连接到一个函数,这个函数就成了一个槽函数。当用户点击按钮时,信号就会被触发,从而导致与之连接的槽函数被调用。

纯C++中如何实现信号和槽?

虽然Qt框架中提供了元对象系统等技术来支持信号和槽的实现,但是我们也可以使用纯C++代码来实现信号和槽的机制。下面,我们以一个示例代码来说明纯C++中如何实现信号和槽。

#pragma once
// 槽
class Slot
{
public:
    virtual void execute() = 0;  // 执行槽函数
};
#pragma once
#include "Slot.h"
// 带参数的槽
template <typename T>
class SlotWithData : public Slot
{
public:
    using CallbackType = void (*)(T);

    SlotWithData(CallbackType callback) : m_callback(callback) {}

    void execute() override {}

    void execute(T data)
    {
        m_callback(data);
    }

private:
    CallbackType m_callback;
};
#pragma once
#include <list>
#include "Slot.h"
#include "SlotWithData.h"
// 信号
template <typename T>
class Signal
{
public:
    void connect(Slot* slot);  // 将槽连接到信号
    void disconnect(Slot* slot); // 解除槽与信号的绑定
    

    void emit(T data);  // 发送信号,并执行相关的槽函数

private:
    std::list<Slot*> slots;
};

template<typename T>
inline void Signal<T>::connect(Slot* slot)
{
    slots.push_back(slot);
}

template<typename T>
inline void Signal<T>::disconnect(Slot* slot)
{
    slots.remove(slot);
}

template<typename T>
inline void Signal<T>::emit(T data)
{
    for (auto slot : slots)
    {
        dynamic_cast<SlotWithData<T>*>(slot)->execute(data);
    }
}
#include <iostream>
#include <string>
#include <vector>
#include"Slot.h"
#include "Signal.h"
#include "SlotWithData.h"
using namespace std;


// 槽函数1
void slotFunc1(int data)
{
    cout << "slot1: " << data << endl;
}

// 槽函数2
void slotFunc2(string data)
{
    cout << "slot2: " << data << endl;
}

// 槽函数3
void slotFunc3(int data)
{
    cout << "slot3: " << data << endl;
}
// 槽函数4
void slotFunc4(int data)
{
    cout << "slot4: " << data << endl;
}
// 槽函数5
void slotFunc5(int data)
{
    cout << "slot5: " << data << endl;
}
int main()
{
    Signal<int> signal1;  // 整型信号
    Signal<string> signal2;  // 字符串信号
    int in=0;
    Slot* slot1 = new SlotWithData<int>(&slotFunc1);  // 将槽与函数绑定
    Slot* slot2 = new SlotWithData<string>(&slotFunc2);
    Slot* slot3 = new SlotWithData<int>(&slotFunc3);  // 将槽与函数绑定
    Slot* slot4 = new SlotWithData<int>(&slotFunc4);  // 将槽与函数绑定
    Slot* slot5 = new SlotWithData<int>(&slotFunc5);  // 将槽与函数绑定
    signal1.connect(slot1);  // 将槽连接到信号
    signal2.connect(slot2);
    signal1.connect(slot3);  // 将槽连接到信号
    signal1.connect(slot4);  // 将槽连接到信号
    signal1.connect(slot5);  // 将槽连接到信号
    while (true)
    {
        cin >> in;
        switch (in)
        {
        case 1:
            signal1.emit(in);  // 发送信号,并执行相关的槽函数
            break;
        case 2:
            signal2.emit(std::to_string(in));
            break;
        default:
            break;
        }
        
       
    }

    signal1.disconnect(slot1);
    signal2.disconnect(slot2);
    signal1.disconnect(slot3);
    signal1.disconnect(slot4);
    signal1.disconnect(slot5);
    delete slot1;
    delete slot2;
    delete slot3;
    delete slot4;
    delete slot5;
    return 0;
}

// 运行程序: Ctrl + F5 或调试 >“开始执行(不调试)”菜单
// 调试程序: F5 或调试 >“开始调试”菜单

在这个示例代码中,定义了一个名为Signal的模板类,它包含了connect、disconnect和emit三个函数。其中connect函数用于将槽与信号绑定在一起,disconnect函数用于解除该绑定关系,emit函数用于发送信号并执行对应的槽函数。

实现connect和disconnect函数时,我们使用std::list来存储槽函数。由于链表本身是按照添加顺序存储的,因此我们就能够支持一个信号对应多个槽函数的情况了。

在SlotWithData类中,我们定义了一个回调函数指针CallbackType,以及execute函数用于执行槽函数。当执行execute函数时,我们调用回调函数指针,并传递对应的参数data,从而实现信号和槽之间的数据交换。

在程序的主函数中,我们定义了两个信号signal1和signal2,分别对应整型和字符串类型。然后我们将两个槽函数slotFunc1和slotFunc2与这两个信号绑定起来。当使用emit函数发送信号时,与之连接的所有槽函数就会被执行。

最后,我们还添加了disconnect函数用于解除信号与槽的绑定,确保我们可以方便地添加、移除槽函数以及通知信号触发相应的槽函数。

总结

通过这篇博客的介绍,我们了解了如何在纯C++代码中实现信号和槽机制。尽管Qt框架提供了更加灵活和完善的支持,但是通过自己手动实现信号和槽机制,可以帮助我们更好地理解其底层机制,并且在开发一些嵌入式系统等环境下,也能够帮助我们实现基础的信号和槽功能。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

什么是信号和槽?纯C++中如何实现信号和槽? 的相关文章

  • C++:无法使用scoped_allocator_adaptor传播polymorphic_allocator

    我有一个vector
  • 在 Xamarin Android 中将图像从 URL 异步加载到 ImageView 中

    我有一个包含多个项目的 ListView 列表中的每个项目都应该有一个与之关联的图像 我创建了一个数组适配器来保存每个列表项并具有我希望加载的图像的 url 我正在尝试使用 Web 请求异步加载图像 并设置图像并在加载后在视图中更新它 但视
  • C++ 求二维数组每一行的最大值

    我已经设法用这个找到我的二维数组的每一行的最小值 void findLowest int A Cm int n int m int min A 0 0 for int i 0 i lt n i for int j 0 j lt m j if
  • 如何在C++中实现模板类协变?

    是否可以以这样一种方式实现类模板 如果模板参数相关 一个对象可以转换为另一个对象 这是一个展示这个想法的例子 当然它不会编译 struct Base struct Derived Base template
  • 将字符串从非托管代码传递到托管

    我在将字符串从非托管代码传递到托管代码时遇到问题 在我的非托管类中 非托管类 cpp 我有一个来自托管代码的函数指针 TESTCALLBACK FUNCTION testCbFunc TESTCALLBACK FUNCTION 接受一个字符
  • 使用 Google Analytics API 在 C# 中显示信息

    我一整天都在寻找一个好的解决方案 但谷歌发展得太快了 我找不到有效的解决方案 我想做的是 我有一个 Web 应用程序 它有一个管理部分 用户需要登录才能查看信息 在本节中 我想显示来自 GA 的一些数据 例如某些特定网址的综合浏览量 因为我
  • C# 用数组封送结构体

    假设我有一个类似于 public struct MyStruct public float a 我想用一些自定义数组大小实例化一个这样的结构 在本例中假设为 2 然后我将其封送到字节数组中 MyStruct s new MyStruct s
  • 使用向量的 merge_sort 在少于 9 个输入的情况下效果很好

    不知何故 我使用向量实现了合并排序 问题是 它可以在少于 9 个输入的情况下正常工作 但在有 9 个或更多输入的情况下 它会执行一些我不明白的操作 如下所示 Input 5 4 3 2 1 6 5 4 3 2 1 9 8 7 6 5 4 3
  • Windows 10 中 Qt 桌面应用程序的缩放不当

    我正在为 Windows 10 编写一个简单的 Qt Widgets Gui 应用程序 我使用的是 Qt 5 6 0 beta 版本 我遇到的问题是它根本无法缩放到我的 Surfacebook 的屏幕上 这有点难以判断 因为 SO 缩放了图
  • 像“1$”这样的位置参数如何与 printf() 一起使用?

    By man I find printf d width num and printf 2 1 d width num 是等价的 但在我看来 第二种风格应该与以下相同 printf d num width 然而通过测试似乎man是对的 为什
  • C 中的位移位

    如果与有符号整数对应的位模式右移 则 1 vacant bit will be filled by the sign bit 2 vacant bit will be filled by 0 3 The outcome is impleme
  • 可空属性与可空局部变量

    我对以下行为感到困惑Nullable types class TestClass public int value 0 TestClass test new TestClass Now Nullable GetUnderlyingType
  • 检查 url 是否指向文件或页面

    我们需要以下内容 如果文件确实是文件 则从 URL 下载该文件 否则 如果它是一个页面 则什么也不做 举个简单的例子 我有以下命令来下载文件 My Computer Network DownloadFile http www wired c
  • 将应用程序从 Microsoft Access 迁移到 VB 或 C#.NET

    我目前正试图说服管理层需要将我们的应用程序之一移植到 NET 该应用程序已经发展成为 Access 中的一个庞然大物 SQL 后端 拥有 700 个链接表 650 个表单 子表单 130 个模块和 850 个查询 我几乎知道这样做的所有主要
  • char指针或char变量的默认值是什么[重复]

    这个问题在这里已经有答案了 下面是我尝试打印 char 变量和指针的默认值 值的代码 但无法在控制台上看到它 它是否有默认值或只是无法读取 ASCII 范围 include
  • 如何在内存中存储分子?

    我想将分子存储在内存中 这些可以是简单的分子 Methane CH4 C H bond length 108 7 pm H H angle 109 degrees But also more complex molecules like p
  • ListDictionary 类是否有通用替代方案?

    我正在查看一些示例代码 其中他们使用了ListDictionary对象来存储少量数据 大约 5 10 个对象左右 但这个数字可能会随着时间的推移而改变 我使用此类的唯一问题是 与我所做的其他所有事情不同 它不是通用的 这意味着 如果我在这里
  • 在 ASP.NET 中将事件冒泡为父级

    我已经说过 ASP NET 中的层次结构 page user control 1 user control 2 control 3 我想要做的是 当控件 3 它可以是任何类型的控件 我一般都想这样做 让用户用它做一些触发回发的事情时 它会向
  • 将变量分配给另一个变量,并将一个变量的更改反映到另一个变量中

    是否可以将一个变量分配给另一个变量 并且当您更改第二个变量时 更改会瀑布式下降到第一个变量 像这样 int a 0 int b a b 1 现在 b 和 a 都 1 我问这个问题的原因是因为我有 4 个要跟踪的对象 并且我使用名为 curr
  • 不同类型的指针可以互相分配吗?

    考虑到 T1 p1 T2 p2 我们可以将 p1 分配给 p2 或反之亦然吗 如果是这样 是否可以不使用强制转换来完成 或者我们必须使用强制转换 首先 让我们考虑不进行强制转换的分配 C 2018 6 5 16 1 1 列出了简单赋值的约束

随机推荐

  • 线程的基本概念,线程的同步互斥机制

    一 线程的概念 1 1 什么是线程 线程 线程是进程的一个实体 是被系统独立调度和分派的基本单位 是一个进程并发执行多个任务的机制 并发 单核CPU多任务同时运行 CPU以ms级进行进程调度 1 2 为什么引入线程 进程间的切换表现为上下文
  • 计算机设备显示感叹号,设备管理器有感叹号和问号未知设备的解决方法

    设备管理器有感叹号和问号未知设备怎么办 因为在Windows操作系统中 设备管理器是管理计算机硬件设备的工具 我们可以借助设备管理器查看计算机中所安装的硬件设备 设置设备属性 安装或更新驱动程序 停用或卸载设备 可以说是功能非常强大 但有时
  • VC 如何使程序运行后自己删除自己

    VC 如何使程序运行后自己删除自己 有时候 我们需要创建一个运行后能够自己删除自己的可执行程序即自删除程序 很明显如果一个进程通过直接调用DeleteFile 来删除自己是不可能的 必须另想办法 经过本人在网上参考很多资料后实际测试并集众家
  • Onnxruntime-CUDA版本对应

    ONNX Runtime CUDA cuDNN 1 14 1 13 1 1 13 11 6 8 2 4 Linux 8 5 0 96 Windows 1 12 1 11 11 4 8 2 4 Linux 8 2 2 26 Windows 1
  • Flink源码-SlidingProcessTimeWindow的创建和触发

    今天研究了下SlidingProcessTimeWindow的源码 把TimeWindow的生成和触发计算 大致搞清楚了 写一篇博客记录下 要点 这里讲的是ProcessTime的滑动窗口 每条数据都会触发窗口的分配 创建 一条数据可能分配
  • 基于鲸鱼算法优化支持向量机SVM的分类预测,基于WOA-SVM的光谱分类

    目录 支持向量机SVM的详细原理 SVM的定义 SVM理论 鲸鱼算法的原理及步骤 SVM应用实例 基于鲸鱼算法改进SVM的光谱分类 代码 结果分析 展望 支持向量机SVM的详细原理 SVM的定义 支持向量机 support vector m
  • 【qt】error: C2248: “QVariant::QVariant”: 无法访问 private 成员(在“QVari

    错误信息 main A a new A engine rootContext gt setContextProperty a a C2248 QVariant QVariant 无法访问 private 成员 在 QVariant 类中声明
  • Unity发布WebGL如何把文件下载到本地——后续,详细实现。

    Unity发布WebGL如何把文件下载到本地 后续 详细实现 前言 一 编写jslib 二 引入dll 编写C 脚本 三 最终效果 总结 版权声明 前言 以前的问题https blog csdn net Wrinkle2017 articl
  • 10.28 云计算

    课上实验实训1 获取令牌 生效环境变量 source etc keystone admin openrc sh 验证令牌 openstack role list 查看角色列表 openstack user list 查看用户列表 opens
  • Elasticsearch 基础 DSL 命令

    Elasticsearch 基础 DSL 命令 1 模拟请求 2 分词器相关 3 索引库相关 4 文档相关 5 查询相关 6 GEO 查询 7 组合查询 8 得分加权 9 排序 10 分页 11 高亮 Elasticsearch 官方文档
  • vue上传excel文件

  • NLP语言学基础

    不同的自然语言有不同的语法结构 因此需要对语言数据进行语法解析 才能让机器更准确地学到相应的模式 儿语言不同于图像 数据标注工作需要有一定的语言学知识 因此数据的整理也相对更困难 下面以英语为例 别的咱也看不懂 对NLP研究中常见的基本语言
  • mysql运行效率最高的是memory_MySQL数据库的性能的影响分析及其优化

    MySQL数据库的性能的影响分析及其优化 MySQL数据库的性能的影响 一 服务器的硬件的限制 二 服务器所使用的操作系统 三 服务器的所配置的参数设置不同 四 数据库存储引擎的选择 五 数据库的参数配置的不同 六 重点 数据库的结构的设计
  • Android多窗口模式(分屏模式)

    Android N 支持多窗口模式 或者叫分屏模式 即在屏幕上可以同时显示多个窗口 在手机模式下 两个应用可以并排或者上下同时显示 如图 1 所示 屏幕上半部分的窗口是系统的 CLOCK 应用 下半部分是系统设置功能 用户可以拖动两个应用之
  • Chrome浏览器崩溃“STATUS_INVALID_IMAGE_HASH”的解决方法

    原文地址 Chrome浏览器崩溃 STATUS INVALID IMAGE HASH 的解决方法 JUNE S BLOG 六月博客 今天无意间 发现Chrome浏览器多了个 由贵单位管理 的提示 出于安全的考虑 想立马把它搞掉 百度了一堆方
  • 使用TextInputLayout创建一个登陆界面(j界面很漂亮)

    http www jcodecraeer com a basictutorial 2015 0821 3338 html
  • xss、csrf、ssrf的区别

    要想搞懂这三者有什么区别 首先需要知道它们的原理 xss 原理 跨站脚本攻击 攻击分类造成危害为 存储型 gt 反射型 gt DOM型 与SQL注入差不多 SQL注入漏洞是WEB应用程序未对用户输入的参数严格的过滤 导致被攻击者恶意拼接SQ
  • React中使用SVG文件显示成图片

    SVG 没法直接渲染都img 一般引用插件 方案一 使用 create react app脚手架 创建react项目 方案二 file loader 插件 SVG文件优缺点 优点 不失真 放大缩小图像都很清晰 SVG文件是纯粹的XML 也是
  • 'mvn-v' 不是内部或外部命令,也不是可运行的程序 或批处理文件。

    当我下载安装好maven 想通过测试出现看是否配置成功的时候 出现了问题 如下 如何解决 首先我的JDK是没有问题的 就是我的java程序编译都是可以的 那么就应该是配置maven的时候出现了问题 正确的参数的配置如下 1 新建变量 我这里
  • 什么是信号和槽?纯C++中如何实现信号和槽?

    什么是信号和槽 在Qt框架中 信号和槽是一种非常灵活的机制 用于在对象之间进行通信 信号和槽可以将两个对象解耦并连接起来 从而使得一个对象发生变化时 另一个对象就能够接收到相应的通知 并执行相关的操作 例如 在编写一个GUI程序时 我们可以