给出以下代码
#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源文件
打开类似这样的源文件。先从头部慢慢开始往下分析
1. 分析元字符串
文件开头有这样的内容,
下面结构体用于存储这个类所有的字符串信息,包括类名、函数名、元类信息的值
QT_MOC_LITERAL宏用于定位qt_meta_stringdata_qtTest_t结构体的什么位置
给出每个宏的原型
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存储的是关于这个对象的字符串信息。如下图所示
2. 分析元数据
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;
};
具体细节看下图,只是给出了前几个具体什么意思,如果看懂了前几个,也就明白了这个数组具体是怎么回事了。
上图中的下标基本就是指向qt_meta_stringdata_qtTest对象中的字符串,要不就是当前数组qt_meta_data_qtTest中的具体下标
今天先到这里,先去学习其他知识了。明天继续来更新。