当前位置: 首页 > news >正文

Qt中的字符串宏 | 编译期检查和运行期检查 | Qt信号与槽connect写法

一、什么是字符串宏(String Macro)

        字符串宏其实来源于 C/C++ 的预处理器宏(Macro)

宏是什么?

        在 C++ 代码正式编译之前,编译器会先经过一个预处理阶段,在这个阶段,所有的 #define 宏定义都会被纯文本替换

        例如:

#define PI 3.14159

        当你写:

double area = PI * r * r;

        预处理器会在编译前把它替换成:

double area = 3.14159 * r * r;

        这就是宏展开

那么什么是“字符串宏”?

        字符串宏就是返回字符串的宏,也就是说,它展开后不是数字或表达式,而是 字符串字面量(string literal)

        例如:

#define NAME "Landon"

        当代码中出现:

std::cout << NAME;

        编译器看到的其实是:

std::cout << "Landon";

Qt 中的 SIGNAL() / SLOT() 宏就是字符串宏

        在 Qt4 以及早期 Qt5 中,信号和槽连接常写成这样:

connect(spinBox, SIGNAL(valueChanged(int)), label, SLOT(setNum(int)));

表面上看像是函数调用,但其实:

  • SIGNAL()SLOT() 是两个宏;

  • 它们把括号内的内容变成 字符串常量

展开后是这样(伪代码):

connect(spinBox, "2valueChanged(int)", label, "1setNum(int)");

"2""1" 是内部用于区分信号和槽的标识,Qt 的元对象系统(Meta-Object System)会在运行时根据这些字符串去查找信号和槽是否存在

关键点:

SIGNAL 和 SLOT 写法依赖字符串匹配,编译器并不会验证信号或槽的存在

举个例子

connect(spinBox, SIGNAL(valueChaged(int)), label, SLOT(setNum(int)));

        你不小心少写了一个 n(changed被你不小心写为chaged),程序依然能编译通过

        但运行时会出现:

QObject::connect: No such signal QSpinBox::valueChaged(int)

        这就是字符串宏的弊端:

  • 编译器无法检查;

  • 错误要到运行时才发现。

Qt5+ 改进:函数指针写法取代字符串宏

        Qt5 之后,我们可以写:

connect(spinBox, &QSpinBox::valueChanged, label, &QLabel::setNum);

        这种写法不再使用字符串,而是真正的函数指针,编译器能在编译期就检查函数是否存在、参数是否匹配,彻底杜绝拼写错误

二、编译期检查与运行期检查

        在 C++(以及 Qt)编程中,你可能常听到这两个概念:

“这种写法只能运行期报错,而那种写法能在编译期就检查出来”

        那么,究竟什么是 编译期检查(Compile-time Check)运行期检查(Runtime Check) 呢?它们的区别到底是什么?为什么 Qt 推荐我们使用新式connect语法?

        这篇文章帮你彻底搞清楚

程序的两个阶段

        当我们写一个 C++ 程序,它要经过两个重要阶段:

编译期(Compile-time)—— 程序还没运行,编译器正在“检查并生成机器代码”的阶段

运行期(Runtime)—— 程序已经被加载到内存中,正在实际执行的阶段

编译期检查(Compile-time Checking)

定义:

编译器在“编译阶段”发现问题,并阻止程序生成可执行文件

特点:

  • 错误在编译时就会报出

  • 不需要运行程序

  • 一旦出错,编译器立即停止编译

  • 错误更容易定位,更安全

举个例子:

int x = "hello";   // ❌ 类型不匹配

        编译器会直接报错:

error: invalid conversion from 'const char*' to 'int'

        这就是 编译期检查

在 Qt 中的例子:

        旧版写法(Qt4 风格):

connect(spinBox, SIGNAL(valueChanged(int)), label, SLOT(setNum(int)));

        这行代码中的 SIGNAL()SLOT()字符串宏,编译器根本不知道 valueChanged(int)setNum(int) 具体是什么函数!

如果你写成:

connect(spinBox, SIGNAL(valueChanged(QString)), label, SLOT(setNum(int)));

编译器也会 默默通过,但程序运行时会在控制台输出警告:

QObject::connect: No such signal QSpinBox::valueChanged(QString)

这类错误只能 运行时 才被发现,属于运行期检查

运行期检查(Runtime Checking)

程序在运行过程中,才检测并发现错误

特点:

  • 编译器不会报错

  • 程序能编译通过

  • 错误只在程序执行时才暴露

  • 有时会导致程序崩溃或逻辑错误

  • 调试成本高

举个例子:

int arr[3] = {1, 2, 3};
arr[5] = 10;   // ❌ 越界访问

编译器无法发现这个错误,因为它不知道你运行时会访问哪个索引
只有在运行时才会出错(甚至直接崩溃)

Qt 示例

        新式写法(Qt5+ 推荐):

connect(spinBox, QOverload<int>::of(&QSpinBox::valueChanged), label, &QLabel::setNum);

        这里使用了 函数指针 + 模板机制,编译器能在 编译期 就检查:

  • 这个信号是否存在;

  • 参数类型是否匹配;

  • 槽函数是否可调用。

如果你写错类型:

connect(spinBox,QOverload<QString>::of(&QSpinBox::valueChanged),label,&QLabel::setNum);

编译器立即报错:

error: no matching function for call to 'connect'

这就是 编译期检查

三、Qt信号与槽connect写法

        Qt 的 connect() 是信号与槽机制的核心函数,从 Qt4 → Qt5 → Qt6connect() 的写法经历了三次重大进化

Qt 的信号槽机制简介

connect() 的作用是:

把一个 信号(signal) 连接到一个 槽(slot)可调用对象(callable)
当信号发出时,槽函数自动被调用

语法通用结构如下:

connect(sender, signal, receiver, slot);
  • sender:发出信号的对象指针

  • signal:信号函数

  • receiver:接收信号的对象指针

  • slot:接收信号后执行的函数(槽)

Qt 各版本 connect 写法概览

Qt 版本写法类型是否类型安全是否支持重载信号示例
Qt4(老式)宏字符串写法❌ 否(运行期检查)❌ 否connect(obj, SIGNAL(sig(int)), obj2, SLOT(slot(int)));
Qt5(推荐)函数指针写法✅ 是(编译期检查)✅ 是connect(obj, &Class::signal, obj2, &Class2::slot);
Qt5(复杂信号)QOverload 辅助写法✅ 是✅ 是connect(obj, QOverload<int>::of(&Class::signal), obj2, &Class2::slot);
Qt5(Lambda)Lambda 槽函数✅ 是✅ 是connect(obj, &Class::signal, this, [=](int v){ ... });
Qt6(简化)新式 connect(自动推导)✅ 是✅ 是connect(obj, &Class::signal, this, &MyClass::slot); 或省略 receiver

详细讲解每种写法

① 宏字符串写法(Qt4 风格)

connect(spinBox, SIGNAL(valueChanged(int)), label, SLOT(setNum(int)));

 特点:

  • 使用宏 SIGNAL()SLOT()

  • 宏会把参数变为字符串(如 "2valueChanged(int)"

  • Qt 运行时再用反射机制(MOC 系统)去匹配信号槽

缺点:

  • 运行期检查,拼写错误不会被编译器发现

  • 不支持信号重载

  • Qt5 中仍可用,但已被官方标记为不推荐

② 函数指针写法(Qt5 推荐)

        Qt5 引入了 编译期类型检查的函数指针 connect

connect(spinBox, &QSpinBox::valueChanged, label, &QLabel::setNum);

优点:

  • 编译期类型安全

  • 支持重载信号

  • 自动匹配函数签名

  • 拼写错误会编译不通过

  • 支持自动断开(随对象析构自动 disconnect)

原理:

        Qt 利用 C++11 函数指针机制,让编译器能在编译时检查信号与槽参数类型是否兼容

③ 重载信号写法(QOverload)

        某些 Qt 类的信号是 overload(重载) 的,比如 QSpinBox::valueChanged

void valueChanged(int value);
void valueChanged(const QString &text);

        这时候你必须告诉编译器你想连接哪个版本。

QOverload 写法:

connect(spinBox,QOverload<int>::of(&QSpinBox::valueChanged),label,&QLabel::setNum);

        或者:

connect(spinBox,QOverload<const QString &>::of(&QSpinBox::valueChanged),this,&MyWidget::onTextChanged);

 原理:

QOverload<Args...>::of(&Class::signal) 明确指定了信号参数类型

④ Lambda 槽函数写法(Qt5 新增)

        Qt5 开始允许用 Lambda 表达式 作为槽函数,非常方便(如果会用的话)

connect(spinBox, &QSpinBox::valueChanged, this, [=](int value){qDebug() << "SpinBox value:" << value;
});

优点:

  • 不需要定义槽函数

  • 支持捕获外部变量

  • 类型安全

  • 写法简洁

用法补充:

        你可以省略 receiver,Qt 会自动推导:

connect(spinBox, &QSpinBox::valueChanged, [=](int v){qDebug() << v;
});

但要注意:若无 receiver,lambda 的生命周期不受控,最好与 QObject::connect 的返回值配合使用来管理连接

⑤ Qt6 的新写法(自动推导 + 简化)

        Qt6 在 Qt5 基础上进一步简化了 connect 语法,支持自动推导、可选参数:

connect(spinBox, &QSpinBox::valueChanged, this, &MyWidget::updateLabel);

        甚至:

connect(spinBox, &QSpinBox::valueChanged, [=](int v){ qDebug() << v; });

        或者返回连接对象:

auto connection = connect(button, &QPushButton::clicked, this, &MyClass::onClick);
disconnect(connection);  // 随时解除连接

disconnect() 写法也有几种

写法用法说明
disconnect(sender, signal, receiver, slot)断开指定信号槽连接
disconnect(connection)Qt5 起支持,通过保存 connect 返回值断开
disconnect(sender, signal)断开该信号的所有槽
disconnect()断开该对象所有连接
http://www.dtcms.com/a/471616.html

相关文章:

  • 网站建设的投资预算怎么写阿里企业邮箱费用
  • 6网站建设做网站建设银行官网官方网站
  • 网页设计职位廊坊网络推广优化公司
  • 画家网站建设内蒙古赤峰市信息网官网
  • 哈尔滨网站制作专业md5 wordpress
  • 天猫商城官网首页seo关键词优化排名
  • 计算机操作系统 内存管理常见问题(菜鸡自学,非专业)
  • Python下载实战:高效获取网络资源
  • Python高级编程:创建可管理属性的完整指南
  • 维修网站建设网站开发职位要求
  • 网站关键词可以做几个网站建设技术指标
  • 科技公司内蒙古网站制作wordpress本地做好如何改站点地址
  • 沧州网站备案自动做效果图的网站
  • 网站怎么做dns解析网络公司建网站
  • 从网站验证码谈用户体验营销型网站建设个人总结怎么写
  • redis中的hash类型命令
  • 网站建设太金手指六六十一管理软件应用
  • 做百度移动网站吗最好app开发公司
  • OCR数据流转
  • 学做网站论坛教程下载某企业网站建设方案论文
  • 众筹网站建设应该具备哪些资质o2o电商平台系统
  • 网站哪里有一键生成
  • 阿里云里面网站建设网站建站wordpress
  • 健身器材 网站模版wordpress设置教程
  • C++类和对象(访问限定符以及this指针)
  • School Team Contest 2 (Winter Computer School 2010/11) - I. Toys(受限增长字符串)
  • H.265/HEVC NALU结构快速入门:从起始码到Type值识别
  • 初中电脑做网站的软件wordpress商品采集
  • 焦作网站建设哪家公司好网站页面分辨率
  • asp.net 网站建设方案做网站用不用thinkphp