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

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,       // revision
       0,       // classname
       0,    0, // classinfo
       2,   14, // methods
       0,    0, // properties
       0,    0, // enums/sets
       0,    0, // constructors
       0,       // flags
       1,       // signalCount

 // signals: name, argc, parameters, tag, flags
       1,    1,   24,    2, 0x05,

 // slots: name, argc, parameters, tag, flags
       4,    1,   27,    2, 0x0a,

 // signals: parameters
    QMetaType::Void, QMetaType::Int,    3,

 // slots: parameters
    QMetaType::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。

  • 4
    点赞
  • 29
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: Qt是一款流行的跨平台C++框架,有着强大的功能和丰富的类库。Qt的核心机制包括Qt的元对象系统和信号机制Qt的元对象系统是Qt的一个重要特性,它是Qt实现反射的基础。在C++中,反射能够在运行时获取类的信息,如类名、属性、方法等,并在运行时动态地创建、调用对象。Qt的元对象系统通过为每个QObject派生的子类生成一个元对象,实现C++的反射机制。元对象系统使得Qt能够在运行时获取QObject派生类的信息,并提供了一系列函数来操作这些对象。 Qt信号机制Qt的核心机制之一,它用于实现对象之间的通信。信号机制基于发布-订阅模式,其中一个对象发送信号,而另一个对象通过连接到这个信号函数来接收信号并进行相应的处理。信号机制具有松耦合的特性,可以实现对象之间的解耦。 在信号机制中,信号是由QObject派生类定义的特殊函数,用于声明某个特定事件发生时要发送的信号函数是QObject派生类中的普通函数,用于接收这个信号,并且执行相应的处理逻辑。信号通过信号连接函数进行连接,这样当信号触发时,与之连接的函数就会被自动调用。 Qt的元对象系统和信号机制Qt强大功能的基石。元对象系统实现C++的反射机制,允许在运行时获取和操作对象的信息。信号机制使对象之间的通信变得简单和易用,提供了一种灵活而高效的方式来实现对象间的解耦。通过这些核心机制Qt能够帮助开发人员更快速、更简便地开发高质量的跨平台应用程序。 ### 回答2: qt核心机制是指Qt框架的底层机制,主要包括Qt元对象系统和Qt信号原理。 Qt元对象系统是Qt框架中的一个重要概念,它在C++语言的基础上添加了一套元对象(Meta Object)系统。元对象系统在编译过程中生成了额外的代码,使得我们可以在运行时获得更多的对象信息。通过元对象系统,Qt实现信号机制、宏(MOC)编译和反射等功能。元对象系统实际上是一种面向对象的编程方式,通过它可以实现Qt特有的功能,如动态属性、动态信号等。 Qt信号原理是Qt框架中的一个重要特性,用于对象间的通信。信号是一种异步通信方式,通过信号发送者(Sender)发送信号,接收者(Receiver)通过函数(Slot)响应信号信号是通过元对象系统实现的,编译器会在MOC编译阶段解析信号的声明,并在运行时建立连接关系。这种机制使得Qt程序的耦合性更低,灵活性更高,同时也为多线程编程提供了一种方便的方式。 总的来说,Qt核心机制包括了Qt的元对象系统和信号原理。元对象系统为Qt框架提供了反射、动态属性和动态信号等功能,信号机制实现了对象间的异步通信。这些机制使得Qt框架具有高度的可扩展性、灵活性和跨平台性,为开发者提供了一种便捷、高效的方式来构建应用程序。 ### 回答3: Qt是一种跨平台的应用程序框架,具有丰富的功能和强大的性能。Qt核心机制是指Qt框架的基础机制,包括Qt元对象系统和Qt信号原理。 Qt元对象系统是Qt框架的核心组成之一,用于实现Qt的一些特殊功能,如信号机制和动态属性。Qt元对象系统通过将所有的类对象都派生自QObject基类,实现了一种反射机制,使得对象之间可以动态地连接和交互。通过使用元对象系统,Qt可以实现面向对象编程的高级特性,如对象间的信号的连接,对象的属性系统以及对象的内省(即动态获取对象的属性和方法信息)等。 Qt信号原理是Qt框架实现事件驱动的关键机制信号机制允许不同对象之间进行松散的耦合,通过信号的方式进行通信。信号是一种特殊的成员函数,用于表示某个事件的发生,是一种普通的成员函数,用于响应信号的发出。当一个信号被发出时,Qt框架会自动将信号进行匹配,并调用对应的函数。这种机制使得对象之间的通信更加灵活和高效,可以实现事件的传递和处理,避免了显式的函数调用和回调函数的使用。 综上所述,Qt的核心机制包括Qt元对象系统和Qt信号原理。通过元对象系统,Qt实现了一种反射机制,使得对象之间可以动态地连接和交互;通过信号机制Qt实现了一种松散耦合的事件处理方式,提高了对象之间的通信效率和灵活性。这些机制Qt框架的重要组成部分,为开发者提供了更加强大和易用的工具和功能。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值