Qt 核心机制源码分析之元对象系统

Qt 核心机制源码分析之元对象系统

在 Qt Core 的官方文档中,介绍了几大核心机制:

本文基于 Qt 6.8 分析 Qt 核心机制的实现,部分细节不进行细究。

元对象系统

元对象系统是后面几个核心机制的基础。所谓的元对象系统,我个人理解是在编译期将类的各种元信息(例如类名、方法名等)编码到程序中,在运行时便可以获取到这些元信息。

元对象系统主要基于:

  1. QObject 类,所有需要使用元对象系统的类都需要继承自 QObject 类,像 Qt 中大部分类都是基于 QObject 的。
  2. Q_OBJECT 宏,可以通过 moc 编译器展开并生成各类元信息,这也是本文重点分析部分。
  3. Moc 编译器。

接下来从一个例子出发:

定义一个头文件 test.h

// test.h
#ifndef TEST_H
#define TEST_H

#include <QObject>

class Test : public QObject {
    Q_OBJECT

    // 属性系统
    Q_PROPERTY(bool testProperty READ getTestProperty WRITE setTestProperty NOTIFY testPropertyChanged)

    enum TestEnum{
        TestEnum_0 = 0,
        TestEnum_1,
    };
    Q_ENUM(TestEnum);

    // 可以看作支持位与的枚举
    enum TestFlag{
        TestFlag_1 = 0x01,
        TestFlag_2 = 0x02,
        TestFlag_4 = 0x04,
    };
    Q_DECLARE_FLAGS(TestFlags, TestFlag);
    Q_FLAGS(TestFlags);

private:
    bool testProperty;

// 信号
signals:
    void signal_1();
    void signal_2(int i);
    void signal_3(int i, int j);

    void testPropertyChanged();

// 槽
public slots:
    void slot_1();
    void slot_2(int i);
    void slot_3(int i, int j);

public:
    bool publicMethod(int arg);
    bool getTestProperty() const;
    void setTestProperty();

private:
    void privateMethod();
};

#endif // TEST_H

在这个例子中,我使用到了 Qt 的属性系统、信号槽、枚举(之前使用moc生成过文件,了解到主要存储这些元信息)。因为分析的目的是想弄明白到底存有哪些元信息?元信息是如何存储的?元信息是如何给予信号槽机制支持的?

接下来使用 moc 编译器生成 moc 文件:

<your qt moc compiler path>/moc.exe test.h > moc_test.cpp

moc_test.cpp 如下(不用细看):

/****************************************************************************
** Meta object code from reading C++ file 'test.h'
**
** Created by: The Qt Meta Object Compiler version 68 (Qt 6.8.0)
**
** WARNING! All changes made in this file will be lost!
*****************************************************************************/

#include "test.h"
#include <QtCore/qmetatype.h>

#include <QtCore/qtmochelpers.h>

#include <memory>


#include <QtCore/qxptype_traits.h>
#if !defined(Q_MOC_OUTPUT_REVISION)
#error "The header file 'test.h' doesn't include <QObject>."
#elif Q_MOC_OUTPUT_REVISION != 68
#error "This file was generated using the moc from 6.8.0. It"
#error "cannot be used with the include files from this version of Qt."
#error "(The moc has changed too much.)"
#endif

#ifndef Q_CONSTINIT
#define Q_CONSTINIT
#endif

QT_WARNING_PUSH
QT_WARNING_DISABLE_DEPRECATED
QT_WARNING_DISABLE_GCC("-Wuseless-cast")
namespace {

#ifdef QT_MOC_HAS_STRINGDATA
struct qt_meta_stringdata_CLASSTestENDCLASS_t {};
constexpr auto qt_meta_stringdata_CLASSTestENDCLASS = QtMocHelpers::stringData(
    "Test",
    "signal_1",
    "",
    "signal_2",
    "i",
    "signal_3",
    "j",
    "testPropertyChanged",
    "slot_1",
    "slot_2",
    "slot_3",
    "testProperty",
    "TestEnum",
    "TestEnum_0",
    "TestEnum_1",
    "TestFlags",
    "TestFlag",
    "TestFlag_1",
    "TestFlag_2",
    "TestFlag_4"
);
#else  // !QT_MOC_HAS_STRINGDATA
#error "qtmochelpers.h not found or too old."
#endif // !QT_MOC_HAS_STRINGDATA
} // unnamed namespace

Q_CONSTINIT static const uint qt_meta_data_CLASSTestENDCLASS[] = {

 // content:
      12,       // revision
       0,       // classname
       0,    0, // classinfo
       7,   14, // methods
       1,   75, // properties
       2,   80, // enums/sets
       0,    0, // constructors
       0,       // flags
       4,       // signalCount

 // signals: name, argc, parameters, tag, flags, initial metatype offsets
       1,    0,   56,    2, 0x06,    4 /* Public */,
       3,    1,   57,    2, 0x06,    5 /* Public */,
       5,    2,   60,    2, 0x06,    7 /* Public */,
       7,    0,   65,    2, 0x06,   10 /* Public */,

 // slots: name, argc, parameters, tag, flags, initial metatype offsets
       8,    0,   66,    2, 0x0a,   11 /* Public */,
       9,    1,   67,    2, 0x0a,   12 /* Public */,
      10,    2,   70,    2, 0x0a,   14 /* Public */,

 // signals: parameters
    QMetaType::Void,
    QMetaType::Void, QMetaType::Int,    4,
    QMetaType::Void, QMetaType::Int, QMetaType::Int,    4,    6,
    QMetaType::Void,

 // slots: parameters
    QMetaType::Void,
    QMetaType::Void, QMetaType::Int,    4,
    QMetaType::Void, QMetaType::Int, QMetaType::Int,    4,    6,

 // properties: name, type, flags, notifyId, revision
      11, QMetaType::Bool, 0x00015103, uint(3), 0,

 // enums: name, alias, flags, count, data
      12,   12, 0x0,    2,   90,
      15,   16, 0x1,    3,   94,

 // enum data: key, value
      13, uint(Test::TestEnum_0),
      14, uint(Test::TestEnum_1),
      17, uint(Test::TestFlag_1),
      18, uint(Test::TestFlag_2),
      19, uint(Test::TestFlag_4),

       0        // eod
};

Q_CONSTINIT const QMetaObject Test::staticMetaObject = { {
    QMetaObject::SuperData::link<QObject::staticMetaObject>(),
    qt_meta_stringdata_CLASSTestENDCLASS.offsetsAndSizes,
    qt_meta_data_CLASSTestENDCLASS,
    qt_sta
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值