[Qt] 简单分析一下Qt5.15的元对象系统(未更新完,正在更新中...)

123 阅读1分钟

给出以下代码

#include <QObject>
#include <QDebug>

class qtTest : public QObject
{
    Q_OBJECT
public:
    qtTest(QObject *parent = nullptr) : QObject(parent){}
    ~qtTest(){}
    
// 元类信息
    Q_CLASSINFO("name", "张三")
// 元属性
    Q_PROPERTY(QString name READ getName WRITE setName NOTIFY nameChange)
// 元方法
    Q_INVOKABLE void displayInfo()
    {
        qDebug() << "元方法";
    }
// 元枚举的两种方式
    enum Color {
        Red, 
        Green,
    };
    Q_ENUM(Color)

    enum class Animal {
        Dog,
        Cat,
    };
    Q_FLAG(Animal)
    Q_DECLARE_FLAGS(anim, Animal)
// 成员函数
    QString getName()
    {
        return m_name;
    }
    void setName(QString name)
    {
        if (m_name != name)
        {
            m_name = name;
            emit nameChange();
        }
    }
// 信号
signals:
    void nameChange();
// 槽函数
public slots:
    void memberUpdate()
    {
        m_name = "测试";
    }
// 成员变量
private:
    QString m_name;
};

对于以上代码,执行编译,分析下moc产生的cpp源文件

image.png

打开类似这样的源文件。先从头部慢慢开始往下分析

1. 分析元字符串

文件开头有这样的内容, image.png

下面结构体用于存储这个类所有的字符串信息,包括类名函数名元类信息的值 image.png

QT_MOC_LITERAL宏用于定位qt_meta_stringdata_qtTest_t结构体的什么位置

image.png 给出每个宏的原型

Q_STATIC_BYTE_ARRAY_DATA_HEADER_INITIALIZER_WITH_OFFSET(size, offset)
typedef qptrdiff qintptr;
offsetof(s,m) ((::size_t)&reinterpret_cast<char const volatile&>((((s*)0)->m)))

再看下上面的offsetof宏转最终被换成下面这样

((qt_meta_stringdata_qtTest_t*)0)->stringdata0,这个宏也就是获得stringdata0在结构体中的偏移量

qptrdiff就将offsetof宏得出的偏移量转换成qintptr类型。

最终的计算公式也就是:

sizeof(QByteArrayData) * 13 + ofs - idx * sizeof(QByteArrayData)

QT_MOC_LITERAL宏根据传入的参数得出在结构体qt_meta_stringdata_qtTest_t中的偏移值

所以,qt_meta_stringdata_qtTest对象中data成员存储的是字符串的偏移值,stringdata0存储的是关于这个对象的字符串信息。如下图所示

image.png

2. 分析元数据

image.png

moc生成了对应的注释,帮助我们理解代码更加容易写。对于content部分,qt定义了一个类型QMetaObjectPrivate,content则对于这个结构体

struct QMetaObjectPrivate
{
    int revision;
    int className;
    int classInfoCount, classInfoData;
    int methodCount, methodData;
    int propertyCount, propertyData;
    int enumeratorCount, enumeratorData;
    int constructorCount, constructorData;
    int flags;
    int signalCount;
};

具体细节看下图,只是给出了前几个具体什么意思,如果看懂了前几个,也就明白了这个数组具体是怎么回事了。 image.png 上图中的下标基本就是指向qt_meta_stringdata_qtTest对象中的字符串,要不就是当前数组qt_meta_data_qtTest中的具体下标


今天先到这里,先去学习其他知识了。明天继续来更新。