Qt 核心机制源码分析之元对象系统
在 Qt Core 的官方文档中,介绍了几大核心机制:
- The Meta-Object System 元对象系统
- The Property System 属性系统
- Object Model 对象模型
- Object Trees & Ownership 对象树和所有权
- Signals & Slots 信号与槽机制
本文基于 Qt 6.8 分析 Qt 核心机制的实现,部分细节不进行细究。
元对象系统
元对象系统是后面几个核心机制的基础。所谓的元对象系统,我个人理解是在编译期将类的各种元信息(例如类名、方法名等)编码到程序中,在运行时便可以获取到这些元信息。
元对象系统主要基于:
- QObject 类,所有需要使用元对象系统的类都需要继承自 QObject 类,像 Qt 中大部分类都是基于 QObject 的。
- Q_OBJECT 宏,可以通过 moc 编译器展开并生成各类元信息,这也是本文重点分析部分。
- 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

最低0.47元/天 解锁文章

被折叠的 条评论
为什么被折叠?



