关于Qt C++中connect的几种写法

目录

1. 传统的槽函数写法

2. 使用函数指针的connect写法(5.0)

3. Lambda表达式作为槽函数(C++11)

4.使用QOverload选择重载信号的写法


connect函数就像是编程世界里的“茴”字,千变万化,各有千秋。咱们程序员呢,就像是孔乙己那样,虽然有时候会觉得这些变化有些好笑,甚至有些令人头疼,但说到底,还不是得乖乖地学着、用着,毕竟这可是编程里的“必备技能”。connect的编写每个人都有自己的习惯,也有其特点,还是要深究一下的。

在Qt中,connect函数用于将信号(signal)与槽(slot)连接起来,以便在信号被发射时自动调用槽函数。Qt提供了几种不同的connect写法,以及定义槽函数的方式,它们各有特点和适用场景。

1. 传统的槽函数写法

在传统的Qt项目中,槽函数通常是在类的头文件中使用slots:关键字声明的特殊成员函数。例如:

class MainWindow : public QMainWindow {Q_OBJECTpublic:MainWindow(QWidget *parent = nullptr);~MainWindow();private slots: // 使用slots关键字声明槽函数void onCalculateClicked();// ... 其他成员和槽函数 ...
};

然后在源文件中实现这个槽函数:

void MainWindow::onCalculateClicked() {// 槽函数的实现
}

使用这种写法时,conect函数通常这样调用:

connect(pbt, SIGNAL(clicked()), this, SLOT(onCalculateClicked()));

这里使用的是SIGNAL()SLOT()宏来将信号和槽转换为字符串形式的标识符。

2. 使用函数指针的connect写法(5.0)

在5.0及后续的Qt版本中,推荐使用函数指针的connect写法,因为它提供了更好的类型检查和编译时错误检测。这种写法不需要使用slots:关键字或SIGNAL()/SLOT()宏,而是直接使用函数指针。例如:

connect(pbt, &QPushButton::clicked, this, &MainWindow::onCalculateClicked);

在这种写法中,&QPushButton::clicked是信号clicked的函数指针,&MainWindow::onCalculateClicked是槽函数的函数指针。编译器会在编译时检查这些指针是否匹配。这种写法的优点如下:

  1. 类型安全
    函数指针的connect写法提供了编译时的类型检查。这意味着如果信号和槽的函数签名不匹配,或者指定的函数不存在,编译器会立即给出错误提示。这大大减少了运行时错误的可能性,因为所有的连接都是在编译时验证的。

  2. 易于阅读和维护
    使用函数指针使得代码更加直观和易于理解。你可以直接看到哪个信号被连接到了哪个槽,而不需要通过字符串来间接表示。这有助于代码的维护和调试,因为你可以更容易地跟踪信号和槽之间的连接关系。

  3. 自动处理函数重载
    当存在多个重载的信号或槽函数时,使用函数指针可以自动选择正确的重载版本。传统的SIGNAL()SLOT()宏在处理重载函数时可能会遇到问题,因为它们依赖于函数名的字符串表示,无法区分重载的函数。而函数指针则包含了函数的完整签名,因此可以准确地选择所需的函数。

  4. 提高性能
    虽然性能差异可能不是非常显著,但使用函数指针的connect写法可能比使用字符串的宏稍微快一些。这是因为函数指针可以直接在编译时解析和连接,而不需要在运行时进行字符串比较和查找。

  5. 与现代C++标准兼容
    随着C++标准的不断发展,使用函数指针的connect写法更符合现代C++的编程风格。它利用了C++11及更高版本中的特性,如lambda表达式和智能指针,使得Qt的代码可以与这些现代特性更好地集成。

  6. 减少宏的使用
    减少宏的使用可以降低代码的复杂性和潜在的错误。宏在C++中经常是导致难以调试的问题的源头,因为它们是在预处理阶段展开的,而不是在编译阶段进行类型检查的。使用函数指针可以避免这些问题。

3. Lambda表达式作为槽函数(C++11)

在C++11以后,除了传统的槽函数和函数指针,Qt还支持使用Lambda表达式作为槽函数。这种写法非常灵活,因为它允许你在connect调用中直接编写槽函数的代码,而不需要在类中定义额外的成员函数。例如:

connect(pbt, &QPushButton::clicked, this, [this]() {// Lambda表达式作为槽函数的实现bool isOK;double r = lEdit->text().toDouble(&isOK);if (isOK && r >= 0) {lab2->setText(QString::number(AreaCircal(r)));} else {lab2->setText("请输入合法的半径!");}
});

这种写法的优点如下:

  1. 捕获或引用捕获的方式来控制这些变量的生命周期和作用域。

  2. 灵活性和动态性
    Lambda表达式提供了一种灵活的方式来定义槽函数的行为。你可以在connect调用中直接编写Lambda表达式,而不需要事先在类中声明槽函数。这使得你可以根据需要在运行时动态地定义槽函数的行为。

  3. 减少代码量
    使用Lambda表达式作为槽函数可以减少需要编写的代码量。你不需要为每个槽函数都声明一个成员函数,这不仅可以减少代码量,还可以使代码更加紧凑和易于管理。

  4. 类型安全
    与传统的字符串宏相比,使用Lambda表达式作为槽函数提供了更好的类型安全。编译器会在编译时检查Lambda表达式的类型是否与信号的参数类型匹配,从而避免了运行时错误。

除了第一种传统写法外,现在较为流行的二、三种写法对比分析如下:

特性Lambda表达式函数指针
引入时间C++11C++早期版本、Qt5.0
定义方式匿名函数,直接在代码中定义需要显式声明和定义函数,然后通过函数指针指向该函数
语法简洁性简洁,直接在调用处定义相对繁琐,需要额外的函数声明和定义
类型推断支持,编译器可根据上下文推断类型不支持,需要显式指定函数返回类型和参数类型
捕获外部变量可以捕获外部作用域中的变量无法直接捕获外部变量,只能访问函数参数
执行环境在新的栈帧中执行,具有独立的调用环境和栈空间指向已存在的函数,不拥有独立的栈空间
灵活性适用于简单的、单行表达式的场合,易于在需要的时间和地点实现功能闭包适用于调用已经定义好的函数,支持动态绑定和回调函数
代码重用性通常用于一次性或短暂的函数定义,代码重用性较低可以通过函数指针在不同位置调用同一函数,代码重用性较高
类型安全性类型安全,编译器检查函数签名类型安全性较低,容易出现类型不匹配的问题
性能现代编译器优化后性能损失可忽略,但在某些情况下可能带来轻微开销通常性能开销较低,但间接调用可能带来一些额外开销
使用场景适用于需要定义简单匿名函数的场景,如STL算法中的排序和过滤适用于需要动态调用不同函数或实现回调函数的场景,如事件处理、插件系统等

上述三种方法的特点和区别总结:

  • 传统槽函数:易于阅读和维护,特别是在槽函数逻辑复杂或需要多次重用的情况下。但是,它们增加了类的复杂度,因为需要在头文件中声明槽函数。
  • 函数指针的connect:提供了更好的类型安全性,减少了运行时错误的可能性。它是现代Qt编程的推荐方式。
  • Lambda表达式:非常灵活,适用于简单的、一次性的槽函数逻辑。但是,如果Lambda表达式过于复杂,可能会降低代码的可读性。

4.使用QOverload选择重载信号的写法(Qt5.7)

使用QOverload选择重载信号的写法同样是在Qt5引入的,在Qt框架中具有显著的优点,并且适用于特定的场景。例如使用comboBox时,有时使用索引,有时使用字符串作为参数:
 

    QComboBox *comboBox = new QComboBox;QLabel *label = new QLabel;label->setText("初始文本");// 添加一些选项到组合框comboBox->addItem("选项 1");comboBox->addItem("选项 2");comboBox->addItem("选项 3");// 使用 QOverload 来连接重载的信号到不同的槽QObject::connect(comboBox, QOverload<int>::of(&QComboBox::currentIndexChanged),[](int index){ qDebug() << "当前索引改变:" << index; });QObject::connect(comboBox, QOverload<const QString&>::of(&QComboBox::currentIndexChanged),[](const QString &text){ qDebug() << "当前文本改变:" << text; });

在这个例子中,currentIndexChanged信号被重载了两次:一次接受一个整型参数(表示当前选中项的索引),另一次接受一个字符串参数(表示当前选中项的文本)。我们使用QOverload模板类来指定我们想要连接的是哪一个重载版本的信号。然后,我们使用lambda表达式来定义当信号发出时执行的代码。QOverload是Qt 5.7及更高版本中引入的一个模板类,它用于在连接重载信号时提供类型安全。在Qt 5.7之前的版本中,您可能需要使用static_cast或函数指针来实现相同的功能,但这样做通常不太安全且容易出错。

具体优点:

  1. 类型安全
    • 使用QOverload可以确保在连接信号和槽时,信号和槽的参数类型完全匹配。这有助于在编译时捕获潜在的错误,提高代码的稳定性。
  2. 清晰明确
    • 通过显式地指定要连接的重载信号版本,代码更加清晰易懂。其他开发者可以一目了然地看到信号和槽之间的对应关系,减少误解和错误。
  3. 灵活性
    • QOverload允许开发者在信号存在多个重载版本的情况下,选择最适合当前需求的信号版本进行连接。这增加了代码的灵活性,使其能够适应不同的场景和需求。
  4. 避免歧义
    • 在没有QOverload之前,如果信号存在多个重载版本,开发者需要通过其他方式(如函数指针转换)来指定要连接的信号版本,这可能会引入歧义和错误。而QOverload提供了一种直接且明确的方式来避免这些问题。

这种写法用于当信号存在多个重载版本时,通过QOverload模板类明确指定要连接的是哪一个重载版本的信号。比如comboBox::currentIndexChanged信号可能有多个重载版本,而通过使用QOverload<int>或QOverload<const QString&>明确指定,然后进行处理。适应场景:

  1. 信号存在多个重载版本
    • 当类中的信号存在多个重载版本时,使用QOverload可以明确指定要连接的重载信号版本,从而避免连接错误或歧义。
  2. 需要类型安全的信号槽连接
    • 在对类型安全要求较高的项目中,使用QOverload可以确保信号和槽的参数类型完全匹配,减少运行时错误的可能性。
  3. 复杂的GUI应用程序
    • 在复杂的GUI应用程序中,信号和槽的连接可能变得非常复杂。使用QOverload可以使代码更加清晰易懂,方便维护和管理。
  4. 需要灵活处理不同参数类型的场景
    • 在某些场景下,可能需要根据不同的参数类型来处理信号。使用QOverload可以方便地选择不同参数类型的信号版本进行连接,从而满足这些需求。

写到这里,感觉有点与孔乙己说的茴字的几种写法行为相仿,这里Qt里的connect函数,简直就是编程界的“茴”字啊!孔乙己要是穿越到编程世界,看到connect的种种写法,怕是要笑得胡子都抖掉了,心里还得嘀咕:“这信号槽的connect,怎地也有如此多般变化,真是绝了!”

想象一下,咱们这connect函数,简直就是编程里的“百搭小能手”,既能跟老式的函数指针眉来眼去,又能跟新潮的Lambda表达式暗送秋波,还能跟那信号映射机制搞点小暧昧。这不,就像孔乙己研究“茴”字的几种写法一样,咱们程序员也得琢磨琢磨connect的几种姿势-_-||b

在选择哪种写法时,应根据具体的需求和代码风格来决定。对于复杂的槽函数逻辑,传统的槽函数可能更合适;对于简单的逻辑或临时的连接,Lambda表达式可能更方便;而函数指针的connect则通常是一个折中的选择,既安全又易于使用。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/60091.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

反向代理模块

1 概念 1.1 反向代理概念 反向代理是指以代理服务器来接收客户端的请求&#xff0c;然后将请求转发给内部网络上的服务器&#xff0c;将从服务器上得到的结果返回给客户端&#xff0c;此时代理服务器对外表现为一个反向代理服务器。 对于客户端来说&#xff0c;反向代理就相当于…

用jquery做一个websocket客户端

先看效果图&#xff1a; 功能很简单&#xff0c;就是作为客户端连接websocket&#xff0c;并实现接受和发送消息。具体代码如下&#xff1a; <!DOCTYPE html> <html lang"zh-cn"> <head><meta charset"UTF-8"><meta name"…

抽象java入门1.5.3.2——类的进阶(中)

前期回顾&#xff1a;抽象java入门1.5.3.1——类的进阶https://blog.csdn.net/c_yanxin_ru/article/details/140858898?spm1001.2014.3001.5501 总结&#xff1a; 在代码溯源中&#xff0c;我发现了一个奇怪的东西&#xff0c;就是OUT不是类中类&#xff08;不是常规类的写法…

蓝桥杯每日真题 - 第17天

题目&#xff1a;&#xff08;最大数字&#xff09; 题目描述&#xff08;13届 C&C B组D题&#xff09; 题目分析&#xff1a; 操作规则&#xff1a; 1号操作&#xff1a;将数字加1&#xff08;如果该数字为9&#xff0c;变为0&#xff09;。 2号操作&#xff1a;将数字…

Ease Monitor 会把基础层,中间件层的监控数据和服务的监控数据打通,从总体的视角提供监控分析

1. 产品定位 Ease Monitor 有如下的产品定位&#xff1a; 关注于整体应用的SLA。 主要从为用户服务的 API 来监控整个系统。 关联指标聚合。 把有关联的系统及其指示聚合展示。主要是三层系统数据&#xff1a;基础层、平台中间件层和应用层。 快速故障定位。 对于现有的系统…

3D Gaussian Splatting 代码层理解之Part2

现在让我们来谈谈高斯分布。我们已经在Part1介绍了如何根据相机的位置获取 3D 点并将其转换为 2D。在本文中,我们将继续处理高斯泼溅的高斯部分,这里用到的是代码库 GitHub 中part2。 我们在这里要做的一个小改动是,我们将使用透视投影,它利用与上一篇文章中所示的内参矩阵…

一道算法期末应用题及解答

1&#xff0e;印刷电路板布线区划分成为n m 个方格&#xff0c;确定连接方格a 到方格b 的最短布线方案。 在布线时&#xff0c;只能沿直线或者直角布线&#xff0c;为避免交叉&#xff0c;已经布线的方格做了封锁标记&#xff0c;其他线路不允许穿过被封锁的方格&#xff0c;某…

揭开广告引擎的神秘面纱:如何在0.1秒内精准匹配用户需求?

目录 一、广告系统与广告引擎介绍 &#xff08;一&#xff09;广告系统与广告粗分 &#xff08;二&#xff09;广告引擎在广告系统中的重要性分析 二、广告引擎整体架构和工作过程 &#xff08;一&#xff09;一般概述 &#xff08;二&#xff09;核心功能架构图 三、标…

freertos任务调度学习

首先创建任务&#xff0c;创建好任务后&#xff0c;开启任务调度器&#xff0c;任务才能执行 1.开启任务调度器 2.启动第一个任务 3.任务切换

初始ArKTs 2

一.类 1.1 声明 类声明引入一个新类型&#xff0c;并定义其字段、方法和构造函数。 定义类后&#xff0c;可以使用关键字new创建实例 可以使用对象字面量创建实例 在以下示例中&#xff0c;定义了Person类&#xff0c;该类具有字段firstname和lastname、构造函数和方法full…

在云服务器搭建 Docker

操作场景 本文档介绍如何在腾讯云云服务器上搭建和使用 Docker。本文适用于熟悉 Linux 操作系统&#xff0c;刚开始使用腾讯云云服务器的开发者。如需了解更多关于 Docker 相关信息&#xff0c;请参见 Docker 官方。 说明&#xff1a; Windows Subsystem for Linux&#xff…

【IDER、PyCharm】免费AI编程工具完整教程:ChatGPT Free - Support Key call AI GPT-o1 Claude3.5

文章目录 CodeMoss 简介CodeMoss 的模型集成如何安装和配置 CodeMossIDER 插件安装步骤 CodeMoss 的实战使用AI 问答功能代码优化与解释优化这段代码解释这段代码 文件上传与对话联网查询与 GPT 助手联网查询GPT 助手 提升开发效率的最佳实践结语更多文献 CodeMoss 简介 CodeM…

编译报错:protoc did not exit cleanly. Review output for more information.

目录标题 解决“protoc did not exit cleanly”的报错问题检查.proto文件的语法 解决“protoc did not exit cleanly”的报错问题 今天做的项目需要用到grpc&#xff0c;然后需要编写proto然后编译后实现grpc的具体方法&#xff01; 结果编译的时候报了protoc did not exit cl…

语义分割(semantic segmentation)

语义分割(semantic segmentation) 文章目录 语义分割(semantic segmentation)图像分割和实例分割代码实现 语义分割指将图片中的每个像素分类到对应的类别&#xff0c;语义区域的标注和预测是 像素级的&#xff0c;语义分割标注的像素级的边界框显然更加精细。应用&#xff1a…

【竞技宝】LOL-传奇杯:姿态飞机TP绕后一锤定音

北京时间2024年11月19日,英雄联盟第二届传奇杯正在如火如荼的进行之中。昨天迎来小组赛第四个比赛日,本日一共进行了七场小组赛的对决,那么在昨日上半场的四场比赛中,登场的各支队伍都取得了什么样的表现呢?接下来小宝为大家带来小组赛day4上半场的比赛战报。 OP(宁王队) 0-1 …

网络安全之信息收集-实战-1

请注意&#xff0c;本文仅供合法和授权的渗透测试使用&#xff0c;任何未经授权的活动都是违法的。 实战&#xff1a;补天公益src“吉林通用航空职业技术学院” 奇安信&#xff5c;用户登录https://www.butian.net/Loo/submit?cid64918 域名或ip&#xff1a;https://www.jlth…

【后端】版本控制

版本控制 1. 什么是版本控制&#xff1f; 版本控制&#xff08;Revision control&#xff09;是一种在开发的过程中用于管理我们对文件、目录或工程等内容的修改历史&#xff0c;方便查看更改历史记录&#xff0c;备份以便恢复以前的版本的软件工程技术。简单来说就是用于管理…

【YOLOv11改进[注意力]】引入DA、FCA、SA、SC、SE + 含全部代码和详细修改方式

本文将进行在YOLOv11中引入DA、FCA、SA、SC、SE魔改v11,文中含全部代码、详细修改方式。助您轻松理解改进的方法。 一 DA、FCA、SA、SC、SE ① DA 论文:Dual Attention Network for Scene Segm

【数据结构】链表解析与实战运用(1.8w字超详细解析)

目录 引言 链表概念及结构 链表的优缺点 链表的分类 1.单向或者双向 2.带头或者不带头 3.带循环或者非循环 单链表接口函数的实现 接口函数一览 创建空节点&打印链表 尾部插入 头部插入 尾部删除 头部删除 查找 在pos位置之后插入节点 在pos位置之前插入节…