Qt 信号槽的实现 - DevBean Tech World

Qt 的信号槽和属性系统基于在运行时进行内省的能力,内省意味着,我们可以列出对象的方法和属性列表,并且能够获取有关它们的所有信息,例如其参数类型。C++ 原生并没有提供内省,所以 Qt 提供了一个工具MOC(本质:代码生成器)来支持它,它处理头文件,生成额外的 C++ 文件,这些文件将同程序剩下的部分一起编译。这些生成的 C++ 文件包含了内省所需要的所有信息。

对于信号和槽来说,本身就是普通的函数,用signals(Qt5前被扩展为protected,qt5后为public)、slots、Q_OBJECT、emit、SIGNAL 和 SLOT等进行扩展声明,是为了MOC认识信号和槽。

#define signals public
#define slots /* nothing */

Q_OBJECT 定义了一系列函数和一个静态的 QMetaObject 对象。这些函数由 MOC 在生成的文件中实现。

emit 是一个空的宏。甚至 MOC 也不会处理它。换句话说,emit 其实是可选的,没有什么含义(除了提醒开发者)。

宏仅由预处理器使用,将参数转换成字符串,并且在之前添加一个代码。

内省表:

static const uint qt_meta_data_Counter[] = {// content:7,       // revision0,       // classname0,    0, // classinfo2,   14, // methods0,    0, // properties0,    0, // enums/sets0,    0, // constructors0,       // flags1,       // signalCount// signals: name, argc, parameters, tag, flags1,    1,   24,    2, 0x05,// slots: name, argc, parameters, tag, flags4,    1,   27,    2, 0x0a,// signals: parametersQMetaType::Void, QMetaType::Int,    3,// slots: parametersQMetaType::Void, QMetaType::Int,    5,0        // eod
};

qt_meta_data_Counter 是一个 uint 数组,生成代码的时候已经为我们分为五个部分:第一部分 content,也就是内容,分为 9 行。第一行 revision,指明 moc 生成代码的版本号(Qt4 的 moc 生成的代码,该值是 6,也就是相当于 moc v6;Qt5 则是 7)。第二个 classname,也就是类名。这是一个索引,指向字符串表的某一个位置(本例中就是第 0 位)。后面便是类信息 classinfo、函数位置等的信息。总体来说,这个表就是一个索引表。

该表中,我们的表格有两列,第一列是总数,第二列是在这个数组中描述开始的索引,可看出定义了两个函数,函数描述的开始位置是索引 14。

函数描述由 5 个 int 组成。第一个是名字,这实际是其在字符串表(我们会在后面看到字符串表的细节)的索引位置。第二个整型是参数的个数,接下来是一个索引,表明在哪里可以找到这个参数的描述。现在我们先忽略 tag 和 flag 两个数据。对每一个函数,moc 还会保存每一个参数的返回类型、类型以及名字的索引。

信号

MOC 同时实现了信号。它们就是普通的函数,创建了一个指向参数的指针的数组,并将这些传给 QMetaObject::activate 函数。数组的第一个元素是返回值。在我们的例子中,这个值是 0,因为返回值是 void。传给 activate 的第三个参数是信号的索引(本例中是 0)。

// SIGNAL 0
void Counter::valueChanged(int _t1)
{void *_a[] = { 0, const_cast<void*>(reinterpret_cast<const void*>(&_t1)) };QMetaObject::activate(this, &staticMetaObject, 0, _a);
}

调用槽

我们可以利用某个槽在 qt_static_metacall 函数的索引位置来调用这个

void Counter::qt_static_metacall(QObject *_o, QMetaObject::Call _c, int _id, void **_a)
{if (_c == QMetaObject::InvokeMetaMethod) {Counter *_t = static_cast<Counter *>(_o);switch (_id) {case 0: _t->valueChanged((*reinterpret_cast< int(*)>(_a[1]))); break;case 1: _t->setValue((*reinterpret_cast< int(*)>(_a[1]))); break;default: ;}}

索引建立

在每一个 QMetaObject 中,槽、信号以及其它该对象可调用的函数都会分配一个从 0 开始的索引。它们是有顺序的,信号在第一位,然后是槽,最后是其它函数。这个索引在内部被称为相对索引。它们不包含父对象的索引位。

一般而言,我们并不想知道一个比特定类更一般的索引,但是却想包含在继承链中其它函数的索引。为了实现这一点,我们在相对索引的基础上添加一个偏移量,得到绝对索引。

连接机制使用以信号为索引的向量。

连接是怎样工作的?

Qt 会去查找元对象的字符串表来找出相应的索引。

创建一个 QObjectPrivate::Connection 对象,将其添加到内部的链表中。

为每一个信号添加一个已连接的槽的列表。每一个连接都必须包含接收对象和槽的索引。这是双向链表,连接使用正向连接链表,断开连接使用反向连接链表。

发出信号

当我们调用信号时,实际是调用 MOC 生成的代码,而这部分代码是调用了 QMetaObject::activate。

c++基础学习之QT 信号和槽机制的底层实现相关推荐

  1. Qt基础之四:Qt信号与槽机制原理及优缺点

    目录 一.简介 二.信号和槽 三.信号(signals) 四.槽(slots) 五.在Qt中使用第三方的Signals和Slots 信号

  2. Qt 信号和槽机制 优点 效率的详解

    一.信号和槽机制 Qt提供了信号和槽机制用于完成界面操作的响应,是完成任意两个Qt对象之间的通信机制. 其中,信号会在某个特定情况或动作下被触发,槽是等同于接收并处理信号的函数. 二..信号和槽机制的 ...

  3. QT信号与槽机制需要注意的问题

    1.信号与槽的效率是非常高的,但是同真正的回调函数比较起来,由于增加了灵活性,因此在速度上还是有所损失.当然这种损失相对来说是比较小的,但是要追求高效率的话,比如实时系统,就要尽可能避免. 2.信号与 ...

  4. QT信号和槽机制分析

    QObject这个class是QT对象模型的核心,绝大部分的 QT 类都是从这个类继承而来.这个模型的中心特征就是一个叫做信号和槽(signal and slot)的机制来实现对象间的通讯,你可以把一 ...

  5. Qt信号与槽机制详解1-创建一个带信号和槽的例子

    目录 一.编译一个例子 1.hello.h中的内容 2.hello.cpp的内容 3.main.cpp中的内容 4.tutorial.pro内容 二.moc_hello.cpp文件 1.Q_OBJEC ...

  6. QT信号与槽——观察者模式——回调函数

    QT信号与槽--观察者模式--回调函数 1.QT信号与槽机制 1.1信号本质 信号是由于用户对窗口或控件进行了某些操作,导致窗口或控件产生了某个特定事件,这时候 Qt 对应的窗口类会发出某个信号.比如 ...

  7. QT5开发及实例学习之二信号和槽机制

    文章目录 前言 一.信号与槽机制的连接方式 二.信号与槽机制的优点 三.信号与槽机制的效率 前言 Qt提供了信号和槽机制用于完成界面操作的响应,信号和槽机制是完成任意两个Qt对象之间的通信机制.其中, ...

  8. QT学习小结之信号与槽

    信号与槽函数是我们学习QT必备的基础知识,今天跟大家分享我学习QT的一些总结吧. 信号槽机制是Qt编程的基础.通过信号槽,能够使Qt各组件在不知道对方的情形下能够相互通讯. 槽函数和普通的C++成员函 ...

  9. Qt 信号与槽基础操作

    文章目录 1.一对多(一个信号对应多个槽) 2.多对一(多个信号连接多个槽) 3.断开连接 4.动态属性 5.对象树 6.QWidget介绍 元对象系统是标准的C++扩展,为Qt提供了信号与槽机制,实 ...

最新文章

  1. 链表中环的入口结点 python_链表中环的入口结点
  2. android studio查看字节码,使用Android studio查看Kotlin的字节码教程
  3. 設備(IE01/IE02/IE03)客製欄位及BAPI處理
  4. .net 识别一维码_天若OCR文字识别 v5.0 原创好用的OCR及翻译小工具
  5. 反卷积可视化工具--deconv-deep-vis-toolbox
  6. mysql的简单实用_MySQL的简单实用 手把手教学
  7. java字符串转字符串数组_Java字符串数组到字符串
  8. Oracle视图编译错误解决办法
  9. mysql 服务器配置信息和运行状态的查看(show variables like)
  10. MySQL 安装 5.0
  11. PT、CT、CVT各是什么意思?
  12. 回想那天让我虎躯一震的bug:Mybatis Ognl引起的异常
  13. Runtime.getRuntime.exec的陷阱
  14. wx小程序工具下载及安装
  15. ubuntu如何卸载软件
  16. html 如何设置选择图片,html中如何设置默认图片?
  17. 如何优化cocos2d程序的内存使用和程序大小
  18. 吹爆这个 pandas GUI 神器,自动转代码!
  19. Chakra-UI——React UI 框架
  20. PPP、HDLC协议配置

热门文章

  1. ribbon负载均衡策略详解
  2. 关于VM安装及其配置CenterOS的步骤
  3. Realsense T265双目+IMU传感器追踪相机的环境配置指南(Ubuntu+Windows)
  4. [网播][podcast] Born to MISrepresent 第十五集:Jouston Huang 谈 Nokia N900
  5. 面试官讲述面试过程 对求职者提出忠告
  6. 【VUE】微商城(一)----安装mint-ui,mui,sass
  7. BWP及TDRA list的RRC/系统消息配置
  8. 【黑金视频连载】FPGA NIOSII视频教程(13)--IIC实验实验
  9. 毕设周报(2023.3.7)
  10. datahub文档_新老DataHub迁移手册