首页 > 编程语言 >从源码角度分析Qt元对象系统

从源码角度分析Qt元对象系统

时间:2023-01-05 15:35:26浏览次数:65  
标签:return Qt int 角度 源码 QMetaObject test const QT


一、演示代码

test.h

#ifndef TEST_H
#define TEST_H

#include <QObject>

class test : public QObject {
Q_OBJECT
public:
Q_INVOKABLE explicit test(QObject *parent = nullptr);

Q_PROPERTY(int a READ f WRITE g)

Q_INVOKABLE void t1();
Q_INVOKABLE int t2(const QString &name, QString mark);

signals:
void sgn1();
int sgn2(int);

public slots:
void slt1();
int slt2(int);

private slots:
void slt3();
int slt4(int);

private:
int f() { return ccc; }
void g(int i) { ccc = i; }
int ccc;
};

#endif // TEST_H

test.cpp

#include "test.h"
#include <QDebug>

test::test(QObject *parent) : QObject(parent) {}

void test::t1() {}

int test::t2(const QString &name, QString mark) {
qDebug() << name << mark;
return 0;
}

void test::slt1() {
qDebug() << "slt1()";
emit sgn1();
}

int test::slt2(int) {
qDebug() << "slt2()";
return 1;
}

void test::slt3() {
qDebug() << "slt3()";
emit sgn2(3);
}

int test::slt4(int) {
qDebug() << "slt4()";
return 1;
}

头文件展开,以及编译后生成:

Q_OBJECT 宏展开


#define Q_OBJECT \
public: \
...
static const QMetaObject staticMetaObject; \
virtual const QMetaObject *metaObject() const; \
virtual void *qt_metacast(const char *); \
virtual int qt_metacall(QMetaObject::Call, int, void **); \
private: \
static void qt_static_metacall(QObject *, QMetaObject::Call, int, void **); \
...

moc_test.cpp

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

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

QT_BEGIN_MOC_NAMESPACE
QT_WARNING_PUSH
QT_WARNING_DISABLE_DEPRECATED
struct qt_meta_stringdata_test_t {
QByteArrayData data[14];
char stringdata0[61];
};
#define QT_MOC_LITERAL(idx, ofs, len) \
Q_STATIC_BYTE_ARRAY_DATA_HEADER_INITIALIZER_WITH_OFFSET(len, \
qptrdiff(offsetof(qt_meta_stringdata_test_t, stringdata0) + ofs \
- idx * sizeof(QByteArrayData)) \
)
static const qt_meta_stringdata_test_t qt_meta_stringdata_test = {
{
QT_MOC_LITERAL(0, 0, 4), // "test"
QT_MOC_LITERAL(1, 5, 4), // "sgn1"
QT_MOC_LITERAL(2, 10, 0), // ""
QT_MOC_LITERAL(3, 11, 4), // "sgn2"
QT_MOC_LITERAL(4, 16, 4), // "slt1"
QT_MOC_LITERAL(5, 21, 4), // "slt2"
QT_MOC_LITERAL(6, 26, 4), // "slt3"
QT_MOC_LITERAL(7, 31, 4), // "slt4"
QT_MOC_LITERAL(8, 36, 2), // "t1"
QT_MOC_LITERAL(9, 39, 2), // "t2"
QT_MOC_LITERAL(10, 42, 4), // "name"
QT_MOC_LITERAL(11, 47, 4), // "mark"
QT_MOC_LITERAL(12, 52, 6), // "parent"
QT_MOC_LITERAL(13, 59, 1) // "a"

},
"test\0sgn1\0\0sgn2\0slt1\0slt2\0slt3\0slt4\0"
"t1\0t2\0name\0mark\0parent\0a"
};
#undef QT_MOC_LITERAL

static const uint qt_meta_data_test[] = {

// content:
8, // revision
0, // classname
0, 0, // classinfo
8, 14, // methods
1, 76, // properties
0, 0, // enums/sets
2, 79, // constructors
0, // flags
2, // signalCount

// signals: name, argc, parameters, tag, flags
1, 0, 54, 2, 0x06 /* Public */,
3, 1, 55, 2, 0x06 /* Public */,

// slots: name, argc, parameters, tag, flags
4, 0, 58, 2, 0x0a /* Public */,
5, 1, 59, 2, 0x0a /* Public */,
6, 0, 62, 2, 0x08 /* Private */,
7, 1, 63, 2, 0x08 /* Private */,

// methods: name, argc, parameters, tag, flags
8, 0, 66, 2, 0x02 /* Public */,
9, 2, 67, 2, 0x02 /* Public */,

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

// slots: parameters
QMetaType::Void,
QMetaType::Int, QMetaType::Int, 2,
QMetaType::Void,
QMetaType::Int, QMetaType::Int, 2,

// methods: parameters
QMetaType::Void,
QMetaType::Int, QMetaType::QString, QMetaType::QString, 10, 11,

// constructors: parameters
0x80000000 | 2, QMetaType::QObjectStar, 12,
0x80000000 | 2,

// properties: name, type, flags
13, QMetaType::Int, 0x00095003,

// constructors: name, argc, parameters, tag, flags
0, 1, 72, 2, 0x0e /* Public */,
0, 0, 75, 2, 0x2e /* Public | MethodCloned */,

0 // eod
};

void test::qt_static_metacall(QObject *_o, QMetaObject::Call _c, int _id, void **_a)
{
if (_c == QMetaObject::CreateInstance) {
switch (_id) {
case 0: { test *_r = new test((*reinterpret_cast< QObject*(*)>(_a[1])));
if (_a[0]) *reinterpret_cast<QObject**>(_a[0]) = _r; } break;
case 1: { test *_r = new test();
if (_a[0]) *reinterpret_cast<QObject**>(_a[0]) = _r; } break;
default: break;
}
} else if (_c == QMetaObject::InvokeMetaMethod) {
auto *_t = static_cast<test *>(_o);
Q_UNUSED(_t)
switch (_id) {
case 0: _t->sgn1(); break;
case 1: { int _r = _t->sgn2((*reinterpret_cast< int(*)>(_a[1])));
if (_a[0]) *reinterpret_cast< int*>(_a[0]) = std::move(_r); } break;
case 2: _t->slt1(); break;
case 3: { int _r = _t->slt2((*reinterpret_cast< int(*)>(_a[1])));
if (_a[0]) *reinterpret_cast< int*>(_a[0]) = std::move(_r); } break;
case 4: _t->slt3(); break;
case 5: { int _r = _t->slt4((*reinterpret_cast< int(*)>(_a[1])));
if (_a[0]) *reinterpret_cast< int*>(_a[0]) = std::move(_r); } break;
case 6: _t->t1(); break;
case 7: { int _r = _t->t2((*reinterpret_cast< const QString(*)>(_a[1])),(*reinterpret_cast< QString(*)>(_a[2])));
if (_a[0]) *reinterpret_cast< int*>(_a[0]) = std::move(_r); } break;
default: ;
}
} else if (_c == QMetaObject::IndexOfMethod) {
int *result = reinterpret_cast<int *>(_a[0]);
{
using _t = void (test::*)();
if (*reinterpret_cast<_t *>(_a[1]) == static_cast<_t>(&test::sgn1)) {
*result = 0;
return;
}
}
{
using _t = int (test::*)(int );
if (*reinterpret_cast<_t *>(_a[1]) == static_cast<_t>(&test::sgn2)) {
*result = 1;
return;
}
}
}
#ifndef QT_NO_PROPERTIES
else if (_c == QMetaObject::ReadProperty) {
auto *_t = static_cast<test *>(_o);
Q_UNUSED(_t)
void *_v = _a[0];
switch (_id) {
case 0: *reinterpret_cast< int*>(_v) = _t->f(); break;
default: break;
}
} else if (_c == QMetaObject::WriteProperty) {
auto *_t = static_cast<test *>(_o);
Q_UNUSED(_t)
void *_v = _a[0];
switch (_id) {
case 0: _t->g(*reinterpret_cast< int*>(_v)); break;
default: break;
}
} else if (_c == QMetaObject::ResetProperty) {
}
#endif // QT_NO_PROPERTIES
}

QT_INIT_METAOBJECT const QMetaObject test::staticMetaObject = { {
&QObject::staticMetaObject,
qt_meta_stringdata_test.data,
qt_meta_data_test,
qt_static_metacall,
nullptr,
nullptr
} };


const QMetaObject *test::metaObject() const
{
return QObject::d_ptr->metaObject ? QObject::d_ptr->dynamicMetaObject() : &staticMetaObject;
}

void *test::qt_metacast(const char *_clname)
{
if (!_clname) return nullptr;
if (!strcmp(_clname, qt_meta_stringdata_test.stringdata0))
return static_cast<void*>(this);
return QObject::qt_metacast(_clname);
}

int test::qt_metacall(QMetaObject::Call _c, int _id, void **_a)
{
_id = QObject::qt_metacall(_c, _id, _a);
if (_id < 0)
return _id;
if (_c == QMetaObject::InvokeMetaMethod) {
if (_id < 8)
qt_static_metacall(this, _c, _id, _a);
_id -= 8;
} else if (_c == QMetaObject::RegisterMethodArgumentMetaType) {
if (_id < 8)
*reinterpret_cast<int*>(_a[0]) = -1;
_id -= 8;
}
#ifndef QT_NO_PROPERTIES
else if (_c == QMetaObject::ReadProperty || _c == QMetaObject::WriteProperty
|| _c == QMetaObject::ResetProperty || _c == QMetaObject::RegisterPropertyMetaType) {
qt_static_metacall(this, _c, _id, _a);
_id -= 1;
} else if (_c == QMetaObject::QueryPropertyDesignable) {
_id -= 1;
} else if (_c == QMetaObject::QueryPropertyScriptable) {
_id -= 1;
} else if (_c == QMetaObject::QueryPropertyStored) {
_id -= 1;
} else if (_c == QMetaObject::QueryPropertyEditable) {
_id -= 1;
} else if (_c == QMetaObject::QueryPropertyUser) {
_id -= 1;
}
#endif // QT_NO_PROPERTIES
return _id;
}

// SIGNAL 0
void test::sgn1()
{
QMetaObject::activate(this, &staticMetaObject, 0, nullptr);
}

// SIGNAL 1
int test::sgn2(int _t1)
{
int _t0{};
void *_a[] = { const_cast<void*>(reinterpret_cast<const void*>(&_t0)), const_cast<void*>(reinterpret_cast<const void*>(&_t1)) };
QMetaObject::activate(this, &staticMetaObject, 1, _a);
return _t0;
}
QT_WARNING_POP
QT_END_MOC_NAMESPACE

二、QMetaObject

QMetaObject 类描述了 QObject 及其派生类对象的所有元信息,该类是 Qt 元对象系
统的核心类,通过该类的成员函数可以获取 QObject 及其派生类对象的所有元信息,
因此可以说 QMetaObject 类的对象是 Qt 中的元对象。

1、获取QMetaObject

QObject中定义了一个虚函数:

virtual const QMetaObject *metaObject() const;

在moc_test.cpp代码,有相应的实现:

const QMetaObject *test::metaObject() const
{
return QObject::d_ptr->metaObject ? QObject::d_ptr->dynamicMetaObject() : &staticMetaObject;
}

2、staticMetaObject

moc_test.cpp中相应代码为:

QT_INIT_METAOBJECT const QMetaObject test::staticMetaObject = { {
&QObject::staticMetaObject,
qt_meta_stringdata_test.data,
qt_meta_data_test,
qt_static_metacall,
nullptr,
nullptr
} };

QMetaObject结构体定义如下:

struct Q_CORE_EXPORT QMetaObject
{
...
struct { // private data
const QMetaObject *superdata;
const QByteArrayData *stringdata;
const uint *data;
typedef void (*StaticMetacallFunction)(QObject *, QMetaObject::Call, int, void **);
StaticMetacallFunction static_metacall;
const QMetaObject * const *relatedMetaObjects;
void *extradata; //reserved for future use
} d;
};

因此可知:superdata指向父类的staticMetaObject,从而形成了对象间的层级链。stringdata指向了qt_meta_stringdata_test.data,data指向了qt_meta_data_test,static_metacall指向了qt_static_metacall。

3、qt_meta_stringdata_test

struct qt_meta_stringdata_test_t {
QByteArrayData data[14];
char stringdata0[61];
};
#define QT_MOC_LITERAL(idx, ofs, len) \
Q_STATIC_BYTE_ARRAY_DATA_HEADER_INITIALIZER_WITH_OFFSET(len, \
qptrdiff(offsetof(qt_meta_stringdata_test_t, stringdata0) + ofs \
- idx * sizeof(QByteArrayData)) \
)
static const qt_meta_stringdata_test_t qt_meta_stringdata_test = {
{
QT_MOC_LITERAL(0, 0, 4), // "test"
QT_MOC_LITERAL(1, 5, 4), // "sgn1"
QT_MOC_LITERAL(2, 10, 0), // ""
QT_MOC_LITERAL(3, 11, 4), // "sgn2"
QT_MOC_LITERAL(4, 16, 4), // "slt1"
QT_MOC_LITERAL(5, 21, 4), // "slt2"
QT_MOC_LITERAL(6, 26, 4), // "slt3"
QT_MOC_LITERAL(7, 31, 4), // "slt4"
QT_MOC_LITERAL(8, 36, 2), // "t1"
QT_MOC_LITERAL(9, 39, 2), // "t2"
QT_MOC_LITERAL(10, 42, 4), // "name"
QT_MOC_LITERAL(11, 47, 4), // "mark"
QT_MOC_LITERAL(12, 52, 6), // "parent"
QT_MOC_LITERAL(13, 59, 1) // "a"

},
"test\0sgn1\0\0sgn2\0slt1\0slt2\0slt3\0slt4\0"
"t1\0t2\0name\0mark\0parent\0a"
};

由上面可知,其保存了元对象的类名、方法名、信号名、槽名、属性名以及各个参数的名字,这些名字主要用来通过名字反射相应的类、方法、信号、槽以及属性等。

4、qt_meta_data_test

static const uint qt_meta_data_test[] = {

// content:
8, // revision
0, // classname
0, 0, // classinfo
8, 14, // methods
1, 76, // properties
0, 0, // enums/sets
2, 79, // constructors
0, // flags
2, // signalCount

// signals: name, argc, parameters, tag, flags
1, 0, 54, 2, 0x06 /* Public */,
3, 1, 55, 2, 0x06 /* Public */,

// slots: name, argc, parameters, tag, flags
4, 0, 58, 2, 0x0a /* Public */,
5, 1, 59, 2, 0x0a /* Public */,
6, 0, 62, 2, 0x08 /* Private */,
7, 1, 63, 2, 0x08 /* Private */,

// methods: name, argc, parameters, tag, flags
8, 0, 66, 2, 0x02 /* Public */,
9, 2, 67, 2, 0x02 /* Public */,

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

// slots: parameters
QMetaType::Void,
QMetaType::Int, QMetaType::Int, 2,
QMetaType::Void,
QMetaType::Int, QMetaType::Int, 2,

// methods: parameters
QMetaType::Void,
QMetaType::Int, QMetaType::QString, QMetaType::QString, 10, 11,

// constructors: parameters
0x80000000 | 2, QMetaType::QObjectStar, 12,
0x80000000 | 2,

// properties: name, type, flags
13, QMetaType::Int, 0x00095003,

// constructors: name, argc, parameters, tag, flags
0, 1, 72, 2, 0x0e /* Public */,
0, 0, 75, 2, 0x2e /* Public | MethodCloned */,

0 // eod
};

以上描述了类、方法、信号、槽以及属性的一些信息。其前面几个字节对应QMetaObjectPrivate结构体:

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_test和qt_meta_data_test基本存储元对象信息。

三、通过QMetaObject获取classInfo

1、classInfo函数

QMetaClassInfo QMetaObject::classInfo(int index) const
{
int i = index;
// classInfoOffset 求父类的偏移
i -= classInfoOffset();
if (i < 0 && d.superdata)
return d.superdata->classInfo(index);

QMetaClassInfo result;
// priv 把d.data转换成QMetaObjectPrivate对象
if (i >= 0 && i < priv(d.data)->classInfoCount) {
result.mobj = this;
result.handle = priv(d.data)->classInfoData + 2*i;
}
return result;
}

可见其主要根据QMetaObjectPrivate中信息,来初始化QMetaClassInfo类。

2、QMetaClassInfo 

函数classInfo中根据QMetaObjectPrivate信息,初始了QMetaClassInfo中mobj和handle。

const char *QMetaClassInfo::name() const
{
if (!mobj)
return 0;
// mobj->d.data[handle] 获取qt_meta_data_test中的数据
// rawStringData 根据index获取qt_meta_stringdata_test.data中字符串
return rawStringData(mobj, mobj->d.data[handle]);
}

const char* QMetaClassInfo::value() const
{
if (!mobj)
return 0;
// mobj->d.data[handle] 获取qt_meta_data_test中的数据
return rawStringData(mobj, mobj->d.data[handle + 1]);
}

static inline const QByteArray stringData(const QMetaObject *mo, int index)
{
Q_ASSERT(priv(mo->d.data)->revision >= 7);
const QByteArrayDataPtr data = { const_cast<QByteArrayData*>(&mo->d.stringdata[index]) };
Q_ASSERT(data.ptr->ref.isStatic());
Q_ASSERT(data.ptr->alloc == 0);
Q_ASSERT(data.ptr->capacityReserved == 0);
Q_ASSERT(data.ptr->size >= 0);
return data;
}

static inline const char *rawStringData(const QMetaObject *mo, int index)
{
return stringData(mo, index).data();
}

四、通过QMetaObject获取constructor

1、constructor函数

QMetaMethod QMetaObject::constructor(int index) const
{
int i = index;
QMetaMethod result;
Q_ASSERT(priv(d.data)->revision >= 2);
// priv 把d.data转换成QMetaObjectPrivate对象
// constructorCount 值为2
if (i >= 0 && i < priv(d.data)->constructorCount) {
result.mobj = this;
// constructorData 值为 79 + 5*i
// 当index=0时,其对应qt_meta_data_test中第79个偏移的位置,即
// constructors: name, argc, parameters, tag, flags
// 0, 1, 72, 2, 0x0e /* Public */,
// 0, 0, 75, 2, 0x2e /* Public | MethodCloned */,
result.handle = priv(d.data)->constructorData + 5*i;
}
return result;
}

可见其主要根据QMetaObjectPrivate中信息,来初始化QMetaMethod类。由上分析可知handle指向qt_meta_data_test的偏移地址,其存储了QMetaMethod中所需要的信息。信息为:

// constructors: name, argc, parameters, tag, flags
0, 1, 72, 2, 0x0e /* Public */,
0, 0, 75, 2, 0x2e /* Public | MethodCloned */,

分别对应构造函数的name, argc, parameters, tag, flags信息。

flags值含义如下:

enum MethodFlags  {
AccessPrivate = 0x00,
AccessProtected = 0x01,
AccessPublic = 0x02,
AccessMask = 0x03, //mask

MethodMethod = 0x00,
MethodSignal = 0x04,
MethodSlot = 0x08,
MethodConstructor = 0x0c,
MethodTypeMask = 0x0c,

MethodCompatibility = 0x10,
MethodCloned = 0x20,
MethodScriptable = 0x40,
MethodRevisioned = 0x80
};

2、QMetaMethod

函数classInfo中根据QMetaObjectPrivate信息,初始了QMetaMethod中mobj和handle。首先我们看下QMetaMethod中的name()函数

2.1 name()

QByteArray QMetaMethod::name() const
{
if (!mobj)
return QByteArray();
// get() 强制转换为QMetaMethodPrivate对象
return QMetaMethodPrivate::get(this)->name();
}

QByteArray QMetaMethodPrivate::name() const
{
return stringData(mobj, mobj->d.data[handle]);
}

static inline const QByteArray stringData(const QMetaObject *mo, int index)
{
// d.stringdata指向qt_meta_stringdata_test.data,其是QByteArrayData数组
// QByteArrayDataPtr data中ptr初始化为QByteArrayData数组地址
const QByteArrayDataPtr data = { const_cast<QByteArrayData*>(&mo->d.stringdata[index]) };
return data;
}

stringData函数分析:mo->d.stringdata指向qt_meta_stringdata_test.data,其值为:

struct qt_meta_stringdata_test_t {
QByteArrayData data[14];
char stringdata0[61];
};

static const qt_meta_stringdata_test_t qt_meta_stringdata_test = {
{
QT_MOC_LITERAL(0, 0, 4), // "test"
QT_MOC_LITERAL(1, 5, 4), // "sgn1"
QT_MOC_LITERAL(2, 10, 0), // ""
QT_MOC_LITERAL(3, 11, 4), // "sgn2"
QT_MOC_LITERAL(4, 16, 4), // "slt1"
QT_MOC_LITERAL(5, 21, 4), // "slt2"
QT_MOC_LITERAL(6, 26, 4), // "slt3"
QT_MOC_LITERAL(7, 31, 4), // "slt4"
QT_MOC_LITERAL(8, 36, 2), // "t1"
QT_MOC_LITERAL(9, 39, 2), // "t2"
QT_MOC_LITERAL(10, 42, 4), // "name"
QT_MOC_LITERAL(11, 47, 4), // "mark"
QT_MOC_LITERAL(12, 52, 6), // "parent"
QT_MOC_LITERAL(13, 59, 1) // "a"

},
"test\0sgn1\0\0sgn2\0slt1\0slt2\0slt3\0slt4\0"
"t1\0t2\0name\0mark\0parent\0a"
};

即mo->d.stringdata[0]返回QT_MOC_LITERAL(0, 0, 4), // "test",类型为QByteArrayData。

#define QT_MOC_LITERAL(idx, ofs, len) \
Q_STATIC_BYTE_ARRAY_DATA_HEADER_INITIALIZER_WITH_OFFSET(len, \
qptrdiff(offsetof(qt_meta_stringdata_test_t, stringdata0) + ofs \
- idx * sizeof(QByteArrayData)) \
)

#define Q_STATIC_BYTE_ARRAY_DATA_HEADER_INITIALIZER_WITH_OFFSET(size, offset) \
Q_STATIC_ARRAY_DATA_HEADER_INITIALIZER_WITH_OFFSET(size, offset)

#define Q_STATIC_ARRAY_DATA_HEADER_INITIALIZER_WITH_OFFSET(size, offset) \
{ Q_REFCOUNT_INITIALIZE_STATIC, size, 0, 0, offset }

QT_MOC_LITERAL构成了一个QByteArrayData数组,而QByteArrayData被重定义为了QArrayData结构体

typedef QArrayData QByteArrayData;
struct Q_CORE_EXPORT QArrayData
{
QtPrivate::RefCount ref;
int size;
uint alloc : 31;
uint capacityReserved : 1;

qptrdiff offset; // in bytes from beginning of header
...
}

/即QT_MOC_LITERAL(0, 0, 4), // "test"展开后变成{ Q_REFCOUNT_INITIALIZE_STATIC, size, 0, 0, offset } ,相当于初始化QArrayData中的ref,size,alloc,capacityReserved,offset几个成员。

回过头来接着看static inline const QByteArray stringData(const QMetaObject *mo, int index)函数:

static inline const QByteArray stringData(const QMetaObject *mo, int index)
{
// d.stringdata指向qt_meta_stringdata_test.data,其是QByteArrayData数组
// QByteArrayDataPtr data中ptr初始化为QByteArrayData数组地址
const QByteArrayDataPtr data = { const_cast<QByteArrayData*>(&mo->d.stringdata[index]) };
return data;
}

struct QByteArrayDataPtr
{
QByteArrayData *ptr;
};

从上可知:QByteArrayDataPtr data中的ptr被初始化成了qt_meta_stringdata_test.data数组地址。并且在返回时转换成了QByteArray对象。那么QByteArrayDataPtr又是如何转换成QByteArray的呢?

我们跟踪QByteArray代码,其提供了一个构造函数:

typedef QTypedArrayData<char> Data;
inline QByteArray(QByteArrayDataPtr dd)
: d(static_cast<Data *>(dd.ptr))
{
}

template <class T>
struct QTypedArrayData
: QArrayData
{
...
}

其调用此构造函数转换成QByteArray,从代码中可知其把dd.ptr转换成了Data结构体,而Data是QTypedArrayData<char>重定义。QTypedArrayData是一个继承QArrayData的模板。QByteArrayDataPtr dd成员变量ptr类型正好是QArrayData。从而整个对应起来了。QArrayData和QTypedArrayData的代码如下:

typedef QArrayData QByteArrayData;
struct Q_CORE_EXPORT QArrayData
{
QtPrivate::RefCount ref;
int size;
uint alloc : 31;
uint capacityReserved : 1;

qptrdiff offset; // in bytes from beginning of header

void *data()
{
Q_ASSERT(size == 0
|| offset < 0 || size_t(offset) >= sizeof(QArrayData));
return reinterpret_cast<char *>(this) + offset;
}
...
}

typedef QTypedArrayData<char> Data;
inline QByteArray(QByteArrayDataPtr dd)
: d(static_cast<Data *>(dd.ptr))
{
}

template <class T>
struct QTypedArrayData
: QArrayData
{
...
}

2.2  QMetaMethod::access()

QMetaMethod::Access QMetaMethod::access() const
{
if (!mobj)
return Private;
// constructorData 值为 79 + 5*i
// 当index=0时,其对应qt_meta_data_test中第79个偏移的位置,即
// constructors: name, argc, parameters, tag, flags
// 0, 1, 72, 2, 0x0e /* Public */,
// 0, 0, 75, 2, 0x2e /* Public | MethodCloned */
// 即mobj->d.data[handle + 4]值为0x0e
return (QMetaMethod::Access)(mobj->d.data[handle + 4] & AccessMask);
}

(mobj->d.data[handle + 4] 值为0x0e,flags代表的含义如下:

enum MethodFlags  {
AccessPrivate = 0x00,
AccessProtected = 0x01,
AccessPublic = 0x02,
AccessMask = 0x03, //mask

MethodMethod = 0x00,
MethodSignal = 0x04,
MethodSlot = 0x08,
MethodConstructor = 0x0c,
MethodTypeMask = 0x0c,

MethodCompatibility = 0x10,
MethodCloned = 0x20,
MethodScriptable = 0x40,
MethodRevisioned = 0x80
};

0x0e为0b0000,1110,可知其访问权限为public,方法类型为constructor。依次类推可以获取访问权限与方法类型,以及方法修订版本(对应方法QMetaMethod::revision(),QMetaMethod::methodType())。

2.3 QMetaMethod::tag()

const char *QMetaMethod::tag() const
{
if (!mobj)
return 0;
return QMetaMethodPrivate::get(this)->tag().constData();
}

QByteArray QMetaMethodPrivate::tag() const
{
Q_ASSERT(priv(mobj->d.data)->revision >= 7);
// constructors: name, argc, parameters, tag, flags
// 0, 1, 72, 2, 0x0e /* Public */,
// 对应值为2,指向第2个字符串,值为空
return stringData(mobj, mobj->d.data[handle + 3]);
}

这个函数可用于注解。其实现示例如:

定义tag,用于注解

// In the class MainWindow declaration
#ifndef Q_MOC_RUN
// define the tag text as empty, so the compiler doesn't see it
# define MY_CUSTOM_TAG
#endif
...
private slots:
MY_CUSTOM_TAG void testFunc();

获取定义的tag,并可解释成特殊用途:

MainWindow win;
win.show();

int functionIndex = win.metaObject()->indexOfSlot("testFunc()");
QMetaMethod mm = win.metaObject()->method(functionIndex);
qDebug() << mm.tag(); // prints MY_CUSTOM_TAG

2.4 QMetaMethod::typeName 获取函数返回名称

const char *QMetaMethod::typeName() const
{
if (!mobj)
return 0;
return QMetaMethodPrivate::get(this)->rawReturnTypeName();
}

const char *QMetaMethodPrivate::rawReturnTypeName() const
{
Q_ASSERT(priv(mobj->d.data)->revision >= 7);
// constructors: parameters
// 0x80000000 | 2, QMetaType::QObjectStar, 12,
// 0x80000000 | 2,
// typesDataIndex() 为72,即typeInfo值为 0x80000000 | 2
// IsUnresolvedType值为0x80000000,所以rawStringData指向第二个字符串
uint typeInfo = mobj->d.data[typesDataIndex()];
if (typeInfo & IsUnresolvedType)
return rawStringData(mobj, typeInfo & TypeNameIndexMask);
else
// methods: parameters
// QMetaType::Void,
// QMetaType::Int, QMetaType::QString, QMetaType::QString, 10, 11,
// 即直接通过QMetaType::QString获取相应的名字类型
return QMetaType::typeName(typeInfo);
}

int QMetaMethodPrivate::typesDataIndex() const
{
Q_ASSERT(priv(mobj->d.data)->revision >= 7);
// constructors: name, argc, parameters, tag, flags
// 0, 1, 72, 2, 0x0e /* Public */,
// 对应值为72
return mobj->d.data[handle + 2];
}

从上面分析可知,其获取流程大致是先通过QMetaObjectPrivate找到构造函数信息,然后依据其信息获取构造函数参数信息,然后根据参数信息获取名称。

2.5 QMetaMethod::parameterNames

QList<QByteArray> QMetaMethod::parameterNames() const
{
if (!mobj)
return QList<QByteArray>();
return QMetaMethodPrivate::get(this)->parameterNames();
}

QList<QByteArray> QMetaMethodPrivate::parameterNames() const
{
// constructors: name, argc, parameters, tag, flags
// 0, 1, 72, 2, 0x0e /* Public */,
// 0, 0, 75, 2, 0x2e /* Public | MethodCloned */,
// 获取参数个数,即argc
int argc = parameterCount();
QList<QByteArray> list;
list.reserve(argc);
// constructors: parameters
// 0x80000000 | 2, QMetaType::QObjectStar, 12,
// 0x80000000 | 2,
// parametersDataIndex 获取参数信息所在的位置,即指向QMetaType::QObjectStar后的12
// 多个参数依次叠加在一起
int namesIndex = parametersDataIndex() + argc;
for (int i = 0; i < argc; ++i)
list += stringData(mobj, mobj->d.data[namesIndex + i]);
return list;
}

int QMetaMethodPrivate::parametersDataIndex() const
{
Q_ASSERT(priv(mobj->d.data)->revision >= 7);
return typesDataIndex() + 1;
}

int QMetaMethodPrivate::typesDataIndex() const
{
Q_ASSERT(priv(mobj->d.data)->revision >= 7);
return mobj->d.data[handle + 2];
}

从上面分析可知,其获取流程大致是先通过QMetaObjectPrivate找到构造函数信息,然后依据其信息获取构造函数参数信息,然后根据参数信息依次获取输入参数信息。

2.6 QMetaMethod::invoke 调用函数

bool QMetaMethod::invoke(QObject *object,
Qt::ConnectionType connectionType,
QGenericReturnArgument returnValue,
QGenericArgument val0,
QGenericArgument val1,
QGenericArgument val2,
QGenericArgument val3,
QGenericArgument val4,
QGenericArgument val5,
QGenericArgument val6,
QGenericArgument val7,
QGenericArgument val8,
QGenericArgument val9) const
{
if (!object || !mobj)
return false;

Q_ASSERT(mobj->cast(object));

// 检查返回类型是否匹配
if (returnValue.data()) {
// 获取返回值类型名
// 与传入的返回值类型名进行比较,不相等则失败返回
const char *retType = typeName();
if (qstrcmp(returnValue.name(), retType) != 0) {
// normalize the return value as well
QByteArray normalized = QMetaObject::normalizedType(returnValue.name());
if (qstrcmp(normalized.constData(), retType) != 0) {
// String comparison failed, try compare the metatype.
int t = returnType();
if (t == QMetaType::UnknownType || t != QMetaType::type(normalized))
return false;
}
}
}

// 检查参数个数是否匹配,不匹配返回false
const char *typeNames[] = {
returnValue.name(),
val0.name(),
val1.name(),
val2.name(),
val3.name(),
val4.name(),
val5.name(),
val6.name(),
val7.name(),
val8.name(),
val9.name()
};
int paramCount;
for (paramCount = 1; paramCount < MaximumParamCount; ++paramCount) {
if (qstrlen(typeNames[paramCount]) <= 0)
break;
}
if (paramCount <= QMetaMethodPrivate::get(this)->parameterCount())
return false;

// 检查连接类型,自动连接则依据是否在同一个线程进行修正
QThread *currentThread = QThread::currentThread();
QThread *objectThread = object->thread();
if (connectionType == Qt::AutoConnection) {
connectionType = currentThread == objectThread
? Qt::DirectConnection
: Qt::QueuedConnection;
}

#if !QT_CONFIG(thread)
if (connectionType == Qt::BlockingQueuedConnection) {
connectionType = Qt::DirectConnection;
}
#endif

// 调用函数
void *param[] = {
returnValue.data(),
val0.data(),
val1.data(),
val2.data(),
val3.data(),
val4.data(),
val5.data(),
val6.data(),
val7.data(),
val8.data(),
val9.data()
};
int idx_relative = QMetaMethodPrivate::get(this)->ownMethodIndex();
int idx_offset = mobj->methodOffset();
Q_ASSERT(QMetaObjectPrivate::get(mobj)->revision >= 6);
// callFunction为static_metacall,即由moc编译器生成的函数
QObjectPrivate::StaticMetaCallFunction callFunction = mobj->d.static_metacall;

if (connectionType == Qt::DirectConnection) {
if (callFunction) {
callFunction(object, QMetaObject::InvokeMetaMethod, idx_relative, param);
return true;
} else {
return QMetaObject::metacall(object, QMetaObject::InvokeMetaMethod, idx_relative + idx_offset, param) < 0;
}
} else if (connectionType == Qt::QueuedConnection) {
if (returnValue.data()) {
// 队列调用不支持返回值
qWarning("QMetaMethod::invoke: Unable to invoke methods with return values in "
"queued connections");
return false;
}

int nargs = 1; // include return type
void **args = (void **) malloc(paramCount * sizeof(void *));
Q_CHECK_PTR(args);
int *types = (int *) malloc(paramCount * sizeof(int));
Q_CHECK_PTR(types);
types[0] = 0; // return type
args[0] = 0;

for (int i = 1; i < paramCount; ++i) {
types[i] = QMetaType::type(typeNames[i]);
if (types[i] == QMetaType::UnknownType && param[i]) {
// Try to register the type and try again before reporting an error.
int index = nargs - 1;
void *argv[] = { &types[i], &index };
QMetaObject::metacall(object, QMetaObject::RegisterMethodArgumentMetaType,
idx_relative + idx_offset, argv);
if (types[i] == -1) {
qWarning("QMetaMethod::invoke: Unable to handle unregistered datatype '%s'",
typeNames[i]);
for (int x = 1; x < i; ++x) {
if (types[x] && args[x])
QMetaType::destroy(types[x], args[x]);
}
free(types);
free(args);
return false;
}
}
if (types[i] != QMetaType::UnknownType) {
args[i] = QMetaType::create(types[i], param[i]);
++nargs;
}
}

QCoreApplication::postEvent(object, new QMetaCallEvent(idx_offset, idx_relative, callFunction,
0, -1, nargs, types, args));
} else { // blocking queued connection
#if QT_CONFIG(thread)
if (currentThread == objectThread) {
qWarning("QMetaMethod::invoke: Dead lock detected in "
"BlockingQueuedConnection: Receiver is %s(%p)",
mobj->className(), object);
}

QSemaphore semaphore;
QCoreApplication::postEvent(object, new QMetaCallEvent(idx_offset, idx_relative, callFunction,
0, -1, 0, 0, param, &semaphore));
semaphore.acquire();
#endif // QT_CONFIG(thread)
}
return true;
}

从上面分析可知,其获取流程大致是调用前检查参数与返回值,修正连接模式。如果是

(1)直连则直接通过static_metacall调用

(2)队列模式,则创建参数,然后通过postEvent放入队列,后期调用static_metacall。

QCoreApplication::postEvent(object, new QMetaCallEvent(idx_offset, idx_relative, callFunction,0, -1, nargs, types, args));

(3)阻塞队列模式

五、通过QMetaObject::indexOfConstructor

int QMetaObject::indexOfConstructor(const char *constructor) const
{
Q_ASSERT(priv(d.data)->revision >= 7);
QArgumentTypeArray types;
QByteArray name = QMetaObjectPrivate::decodeMethodSignature(constructor, types);
return QMetaObjectPrivate::indexOfConstructor(this, name, types.size(), types.constData());
}

// 给定一个方法的签名(如: "foo(int,double)"), 该函数返回参数类型组(QArgumentTypeArray& types)和方法名
QByteArray QMetaObjectPrivate::decodeMethodSignature(
const char *signature, QArgumentTypeArray &types)
{
Q_ASSERT(signature != 0);
const char *lparens = strchr(signature, '(');
if (!lparens)
return QByteArray();
const char *rparens = strrchr(lparens + 1, ')');
if (!rparens || *(rparens+1))
return QByteArray();
int nameLength = lparens - signature;
argumentTypesFromString(lparens + 1, rparens, types);
return QByteArray::fromRawData(signature, nameLength);
}

int QMetaObjectPrivate::indexOfConstructor(const QMetaObject *m, const QByteArray &name,
int argc, const QArgumentType *types)
{
// content:
// 8, // revision
// 0, // classname
// 0, 0, // classinfo
// 8, 14, // methods
// 1, 76, // properties
// 0, 0, // enums/sets
// 2, 79, // constructors
// 0, // flags
// 2, // signalCount
// constructorCount为2,constructorData为79
for (int i = priv(m->d.data)->constructorCount-1; i >= 0; --i) {
int handle = priv(m->d.data)->constructorData + 5*i;
if (methodMatch(m, handle, name, argc, types))
return i;
}
return -1;
}

// Returns \c true if the method defined by the given meta-object&handle
// matches the given name, argument count and argument types, otherwise
// returns \c false.
static bool methodMatch(const QMetaObject *m, int handle,
const QByteArray &name, int argc,
const QArgumentType *types)
{
Q_ASSERT(priv(m->d.data)->revision >= 7);
// constructors: name, argc, parameters, tag, flags
// 0, 1, 72, 2, 0x0e /* Public */,
// 0, 0, 75, 2, 0x2e /* Public | MethodCloned */,
// 比较参数个数
if (int(m->d.data[handle + 1]) != argc)
return false;
// 比较方法名
if (stringData(m, m->d.data[handle]) != name)
return false;

// m->d.data[handle + 2]指向下面数据
// constructors: parameters
// 0x80000000 | 2, QMetaType::QObjectStar, 12,
// 0x80000000 | 2,
// 依次比较参数类型,或者参数名
int paramsIndex = m->d.data[handle + 2] + 1;
for (int i = 0; i < argc; ++i) {
uint typeInfo = m->d.data[paramsIndex + i];
if (types[i].type()) {
if (types[i].type() != typeFromTypeInfo(m, typeInfo))
return false;
} else {
if (types[i].name() != typeNameFromTypeInfo(m, typeInfo))
return false;
}
}

return true;
}

从上面分析可知,其流程大致是先把字符串签名,解析成qt内部的参数和方法名,然后依次与保存的方法信息以及参数信息进行比较。都匹配则返回相应的构造函数方法序号。

六、qt_metacall 与 qt_static_metacall

int test::qt_metacall(QMetaObject::Call _c, int _id, void **_a)
{
_id = QObject::qt_metacall(_c, _id, _a);
if (_id < 0)
return _id;
if (_c == QMetaObject::InvokeMetaMethod) {
if (_id < 8)
qt_static_metacall(this, _c, _id, _a);
_id -= 8;
} else if (_c == QMetaObject::RegisterMethodArgumentMetaType) {
if (_id < 8)
*reinterpret_cast<int*>(_a[0]) = -1;
_id -= 8;
}
#ifndef QT_NO_PROPERTIES
else if (_c == QMetaObject::ReadProperty || _c == QMetaObject::WriteProperty
|| _c == QMetaObject::ResetProperty || _c == QMetaObject::RegisterPropertyMetaType) {
qt_static_metacall(this, _c, _id, _a);
_id -= 1;
} else if (_c == QMetaObject::QueryPropertyDesignable) {
_id -= 1;
} else if (_c == QMetaObject::QueryPropertyScriptable) {
_id -= 1;
} else if (_c == QMetaObject::QueryPropertyStored) {
_id -= 1;
} else if (_c == QMetaObject::QueryPropertyEditable) {
_id -= 1;
} else if (_c == QMetaObject::QueryPropertyUser) {
_id -= 1;
}
#endif // QT_NO_PROPERTIES
return _id;
}

void test::qt_static_metacall(QObject *_o, QMetaObject::Call _c, int _id, void **_a)
{
if (_c == QMetaObject::CreateInstance) {
switch (_id) {
case 0: { test *_r = new test((*reinterpret_cast< QObject*(*)>(_a[1])));
if (_a[0]) *reinterpret_cast<QObject**>(_a[0]) = _r; } break;
case 1: { test *_r = new test();
if (_a[0]) *reinterpret_cast<QObject**>(_a[0]) = _r; } break;
default: break;
}
} else if (_c == QMetaObject::InvokeMetaMethod) {
auto *_t = static_cast<test *>(_o);
Q_UNUSED(_t)
switch (_id) {
case 0: _t->sgn1(); break;
case 1: { int _r = _t->sgn2((*reinterpret_cast< int(*)>(_a[1])));
if (_a[0]) *reinterpret_cast< int*>(_a[0]) = std::move(_r); } break;
case 2: _t->slt1(); break;
case 3: { int _r = _t->slt2((*reinterpret_cast< int(*)>(_a[1])));
if (_a[0]) *reinterpret_cast< int*>(_a[0]) = std::move(_r); } break;
case 4: _t->slt3(); break;
case 5: { int _r = _t->slt4((*reinterpret_cast< int(*)>(_a[1])));
if (_a[0]) *reinterpret_cast< int*>(_a[0]) = std::move(_r); } break;
case 6: _t->t1(); break;
case 7: { int _r = _t->t2((*reinterpret_cast< const QString(*)>(_a[1])),(*reinterpret_cast< QString(*)>(_a[2])));
if (_a[0]) *reinterpret_cast< int*>(_a[0]) = std::move(_r); } break;
default: ;
}
} else if (_c == QMetaObject::IndexOfMethod) {
int *result = reinterpret_cast<int *>(_a[0]);
{
using _t = void (test::*)();
if (*reinterpret_cast<_t *>(_a[1]) == static_cast<_t>(&test::sgn1)) {
*result = 0;
return;
}
}
{
using _t = int (test::*)(int );
if (*reinterpret_cast<_t *>(_a[1]) == static_cast<_t>(&test::sgn2)) {
*result = 1;
return;
}
}
}
#ifndef QT_NO_PROPERTIES
else if (_c == QMetaObject::ReadProperty) {
auto *_t = static_cast<test *>(_o);
Q_UNUSED(_t)
void *_v = _a[0];
switch (_id) {
case 0: *reinterpret_cast< int*>(_v) = _t->f(); break;
default: break;
}
} else if (_c == QMetaObject::WriteProperty) {
auto *_t = static_cast<test *>(_o);
Q_UNUSED(_t)
void *_v = _a[0];
switch (_id) {
case 0: _t->g(*reinterpret_cast< int*>(_v)); break;
default: break;
}
} else if (_c == QMetaObject::ResetProperty) {
}
#endif // QT_NO_PROPERTIES
}

// SIGNAL 0
void test::sgn1()
{
QMetaObject::activate(this, &staticMetaObject, 0, nullptr);
}

// SIGNAL 1
int test::sgn2(int _t1)
{
int _t0{};
void *_a[] = { const_cast<void*>(reinterpret_cast<const void*>(&_t0)), const_cast<void*>(reinterpret_cast<const void*>(&_t1)) };
QMetaObject::activate(this, &staticMetaObject, 1, _a);
return _t0;
}

从上可知,qt_metacall 包含了qt_static_metacall功能。qt_static_metacall主要包含了创建实例、调用方法、属性操作等。因此qt的反射的实现最终实现就是在qt_static_metacall中实现的。

附加属性用法说明:

​​Qt之QFlags及相关宏学习小结 - OSCHINA - 中文开源技术交流社区​​

七、qRegisterMetaType与Q_DECLARE_METATYPE

int id = qRegisterMetaType<MyStruct>();
qRegisterMetaType<MyClass>("MyClass");

此函数可以把类型注册到系统中。qRegisterMetaType函数如下:

template <typename T>
inline int qRegisterMetaType()
{
return qMetaTypeId<T>();
}

template <typename T>
inline int qMetaTypeId()
{
return QMetaTypeId2<T>::qt_metatype_id();
}

template <typename T>
struct QMetaTypeId2
{
enum { Defined = QMetaTypeId<T>::Defined, IsBuiltIn=false };
static inline Q_DECL_CONSTEXPR int qt_metatype_id() { return QMetaTypeId<T>::qt_metatype_id(); }
};

template <typename T>
struct QMetaTypeId : public QMetaTypeIdQObject<T>
{
};

从上面代码可知,qRegisterMetaType经过层层调用,最后调到QMetaTypeIdQObject。QMetaTypeIdQObject也是一个模板,为结构体,其实现如下:

template <typename T, int =
QtPrivate::IsPointerToTypeDerivedFromQObject<T>::Value ? QMetaType::PointerToQObject :
QtPrivate::IsGadgetHelper<T>::IsRealGadget ? QMetaType::IsGadget :
QtPrivate::IsPointerToGadgetHelper<T>::IsRealGadget ? QMetaType::PointerToGadget :
QtPrivate::IsQEnumHelper<T>::Value ? QMetaType::IsEnumeration : 0>
struct QMetaTypeIdQObject
{
enum {
Defined = 0
};
};

其根据QtPrivate::IsPointerToTypeDerivedFromQObject<T>::Value的值,选择不同的模板:

template <typename T>
struct QMetaTypeIdQObject<T*, QMetaType::PointerToQObject>
{
enum {
Defined = 1
};

static int qt_metatype_id()
{
static QBasicAtomicInt metatype_id = Q_BASIC_ATOMIC_INITIALIZER(0);
if (const int id = metatype_id.loadAcquire())
return id;
const char * const cName = T::staticMetaObject.className();
QByteArray typeName;
typeName.reserve(int(strlen(cName)) + 1);
typeName.append(cName).append('*');
const int newId = qRegisterNormalizedMetaType<T*>(
typeName,
reinterpret_cast<T**>(quintptr(-1)));
metatype_id.storeRelease(newId);
return newId;
}
};

template <typename T>
struct QMetaTypeIdQObject<T, QMetaType::IsGadget>
{
enum {
Defined = std::is_default_constructible<T>::value
};

static int qt_metatype_id()
{
static QBasicAtomicInt metatype_id = Q_BASIC_ATOMIC_INITIALIZER(0);
if (const int id = metatype_id.loadAcquire())
return id;
const char * const cName = T::staticMetaObject.className();
const int newId = qRegisterNormalizedMetaType<T>(
cName,
reinterpret_cast<T*>(quintptr(-1)));
metatype_id.storeRelease(newId);
return newId;
}
};

template <typename T>
struct QMetaTypeIdQObject<T*, QMetaType::PointerToGadget>
{
enum {
Defined = 1
};

static int qt_metatype_id()
{
static QBasicAtomicInt metatype_id = Q_BASIC_ATOMIC_INITIALIZER(0);
if (const int id = metatype_id.loadAcquire())
return id;
const char * const cName = T::staticMetaObject.className();
QByteArray typeName;
typeName.reserve(int(strlen(cName)) + 1);
typeName.append(cName).append('*');
const int newId = qRegisterNormalizedMetaType<T*>(
typeName,
reinterpret_cast<T**>(quintptr(-1)));
metatype_id.storeRelease(newId);
return newId;
}
};

template <typename T>
struct QMetaTypeIdQObject<T, QMetaType::IsEnumeration>
{
enum {
Defined = 1
};

static int qt_metatype_id()
{
static QBasicAtomicInt metatype_id = Q_BASIC_ATOMIC_INITIALIZER(0);
if (const int id = metatype_id.loadAcquire())
return id;
const char *eName = qt_getEnumName(T());
const char *cName = qt_getEnumMetaObject(T())->className();
QByteArray typeName;
typeName.reserve(int(strlen(cName) + 2 + strlen(eName)));
typeName.append(cName).append("::").append(eName);
const int newId = qRegisterNormalizedMetaType<T>(
typeName,
reinterpret_cast<T*>(quintptr(-1)));
metatype_id.storeRelease(newId);
return newId;
}
};

我们选择:struct QMetaTypeIdQObject<T*, QMetaType::PointerToQObject>进行分析:

template <typename T>
struct QMetaTypeIdQObject<T*, QMetaType::PointerToQObject>
{
enum {
Defined = 1
};

static int qt_metatype_id()
{
static QBasicAtomicInt metatype_id = Q_BASIC_ATOMIC_INITIALIZER(0);
if (const int id = metatype_id.loadAcquire())
// 已注册,则直接返回注册的id
return id;
const char * const cName = T::staticMetaObject.className();
QByteArray typeName;
typeName.reserve(int(strlen(cName)) + 1);
typeName.append(cName).append('*');
// 注册
const int newId = qRegisterNormalizedMetaType<T*>(
typeName,
reinterpret_cast<T**>(quintptr(-1)));
metatype_id.storeRelease(newId);
return newId;
}
};


template <typename T>
int qRegisterNormalizedMetaType(const QT_PREPEND_NAMESPACE(QByteArray) &normalizedTypeName
#ifndef Q_CLANG_QDOC
, T * dummy = 0
, typename QtPrivate::MetaTypeDefinedHelper<T, QMetaTypeId2<T>::Defined && !QMetaTypeId2<T>::IsBuiltIn>::DefinedType defined = QtPrivate::MetaTypeDefinedHelper<T, QMetaTypeId2<T>::Defined && !QMetaTypeId2<T>::IsBuiltIn>::Defined
#endif
)
{
#ifndef QT_NO_QOBJECT
Q_ASSERT_X(normalizedTypeName == QMetaObject::normalizedType(normalizedTypeName.constData()), "qRegisterNormalizedMetaType", "qRegisterNormalizedMetaType was called with a not normalized type name, please call qRegisterMetaType instead.");
#endif
const int typedefOf = dummy ? -1 : QtPrivate::QMetaTypeIdHelper<T>::qt_metatype_id();
if (typedefOf != -1)
return QMetaType::registerNormalizedTypedef(normalizedTypeName, typedefOf);

QMetaType::TypeFlags flags(QtPrivate::QMetaTypeTypeFlags<T>::Flags);

if (defined)
flags |= QMetaType::WasDeclaredAsMetaType;

const int id = QMetaType::registerNormalizedType(normalizedTypeName,
QtMetaTypePrivate::QMetaTypeFunctionHelper<T>::Destruct,
QtMetaTypePrivate::QMetaTypeFunctionHelper<T>::Construct,
int(sizeof(T)),
flags,
QtPrivate::MetaObjectForType<T>::value());

if (id > 0) {
QtPrivate::SequentialContainerConverterHelper<T>::registerConverter(id);
QtPrivate::AssociativeContainerConverterHelper<T>::registerConverter(id);
QtPrivate::MetaTypePairHelper<T>::registerConverter(id);
QtPrivate::MetaTypeSmartPointerHelper<T>::registerConverter(id);
}

return id;
}

int QMetaType::registerNormalizedType(const NS(QByteArray) &normalizedTypeName,
TypedDestructor destructor,
TypedConstructor constructor,
int size, TypeFlags flags, const QMetaObject *metaObject)
{
return NS(registerNormalizedType)(normalizedTypeName, nullptr, nullptr, destructor, constructor, size, flags, metaObject);
}

static int registerNormalizedType(const NS(QByteArray) &normalizedTypeName,
QMetaType::Destructor destructor,
QMetaType::Constructor constructor,
QMetaType::TypedDestructor typedDestructor,
QMetaType::TypedConstructor typedConstructor,
int size, QMetaType::TypeFlags flags, const QMetaObject *metaObject)
{
// 自定义类型会注册到这个全局变量中
QVector<QCustomTypeInfo> *ct = customTypes();
if (!ct || normalizedTypeName.isEmpty() || (!destructor && !typedDestructor) || (!constructor && !typedConstructor))
return -1;

// 先去全局静态变量中查找(即查找系统自己注册的),没找到则去自定义全局注册变量中查找
int idx = qMetaTypeStaticType(normalizedTypeName.constData(),
normalizedTypeName.size());

int previousSize = 0;
QMetaType::TypeFlags::Int previousFlags = 0;
if (idx == QMetaType::UnknownType) {
QWriteLocker locker(customTypesLock());
int posInVector = -1;
// 在自定义全局注册变量中查找,没有则创建QCustomTypeInfo注册进customTypes()中
idx = qMetaTypeCustomType_unlocked(normalizedTypeName.constData(),
normalizedTypeName.size(),
&posInVector);
if (idx == QMetaType::UnknownType) {
QCustomTypeInfo inf;
inf.typeName = normalizedTypeName;
#ifndef QT_NO_DATASTREAM
inf.loadOp = 0;
inf.saveOp = 0;
#endif
inf.alias = -1;
inf.typedConstructor = typedConstructor;
inf.typedDestructor = typedDestructor;
inf.constructor = constructor;
inf.destructor = destructor;
inf.size = size;
inf.flags = flags;
inf.metaObject = metaObject;
if (posInVector == -1) {
// id为注册序号 + 自定义偏移,即前面为系统默认注册位置,后面才是用户注册的位置
idx = ct->size() + QMetaType::User;
ct->append(inf);
} else {
idx = posInVector + QMetaType::User;
ct->data()[posInVector] = inf;
}
return idx;
}

if (idx >= QMetaType::User) {
previousSize = ct->at(idx - QMetaType::User).size;
previousFlags = ct->at(idx - QMetaType::User).flags;

// Set new/additional flags in case of old library/app.
// Ensures that older code works in conjunction with new Qt releases
// requiring the new flags.
if (flags != previousFlags) {
QCustomTypeInfo &inf = ct->data()[idx - QMetaType::User];
inf.flags |= flags;
if (metaObject)
inf.metaObject = metaObject;
}
}
}

if (idx < QMetaType::User) {
previousSize = QMetaType::sizeOf(idx);
previousFlags = QMetaType::typeFlags(idx);
}

if (Q_UNLIKELY(previousSize != size)) {
qFatal("QMetaType::registerType: Binary compatibility break "
"-- Size mismatch for type '%s' [%i]. Previously registered "
"size %i, now registering size %i.",
normalizedTypeName.constData(), idx, previousSize, size);
}

// these flags cannot change in a binary compatible way:
const int binaryCompatibilityFlag = QMetaType::PointerToQObject | QMetaType::IsEnumeration | QMetaType::SharedPointerToQObject
| QMetaType::WeakPointerToQObject | QMetaType::TrackingPointerToQObject;
if (Q_UNLIKELY((previousFlags ^ flags) & binaryCompatibilityFlag)) {

const char *msg = "QMetaType::registerType: Binary compatibility break. "
"\nType flags for type '%s' [%i] don't match. Previously "
"registered TypeFlags(0x%x), now registering TypeFlags(0x%x). ";

qFatal(msg, normalizedTypeName.constData(), idx, previousFlags, int(flags));
}

return idx;
}

注册大致流程为:若metatype_id有值,则说明已经注册,直接返回注册序号。否则先去系统默认全局注册变量中查找,没找到再去用户注册变量中查找,如果没有说明没有注册,则构建QCustomTypeInfo的信息,并把它注册进用户注册变量中,同时返回用户注册顺序为注册Id。

接下来再分析下系统默认全局注册变量types[]和用户注册变量customTypes(),先看 types[],其查找在qMetaTypeStaticType函数中:

static inline int qMetaTypeStaticType(const char *typeName, int length)
{
int i = 0;
while (types[i].typeName && ((length != types[i].typeNameLength)
|| memcmp(typeName, types[i].typeName, length))) {
++i;
}
return types[i].type;
}

static const struct { const char * typeName; int typeNameLength; int type; } types[] = {
QT_FOR_EACH_STATIC_TYPE(QT_ADD_STATIC_METATYPE)
QT_FOR_EACH_STATIC_ALIAS_TYPE(QT_ADD_STATIC_METATYPE_ALIASES_ITER)
QT_FOR_EACH_STATIC_HACKS_TYPE(QT_ADD_STATIC_METATYPE_HACKS_ITER)
{0, 0, QMetaType::UnknownType}
};

#define QT_ADD_STATIC_METATYPE(MetaTypeName, MetaTypeId, RealName) \
{ #RealName, sizeof(#RealName) - 1, MetaTypeId },

#define QT_ADD_STATIC_METATYPE_ALIASES_ITER(MetaTypeName, MetaTypeId, AliasingName, RealNameStr) \
{ RealNameStr, sizeof(RealNameStr) - 1, QMetaType::MetaTypeName },

#define QT_ADD_STATIC_METATYPE_HACKS_ITER(MetaTypeName, TypeId, Name) \
QT_ADD_STATIC_METATYPE(MetaTypeName, MetaTypeName, Name)

types是一个全局静态结构体数组,包含名称,名称长度以及类型,其通过三个宏,初始化了一系列系统自带的变量,如基本类型(void, bool),基本指针类型,核心类等。

#define QT_FOR_EACH_STATIC_TYPE(F)\
QT_FOR_EACH_STATIC_PRIMITIVE_TYPE(F)\
QT_FOR_EACH_STATIC_PRIMITIVE_POINTER(F)\
QT_FOR_EACH_STATIC_CORE_CLASS(F)\
QT_FOR_EACH_STATIC_CORE_POINTER(F)\
QT_FOR_EACH_STATIC_CORE_TEMPLATE(F)\
QT_FOR_EACH_STATIC_GUI_CLASS(F)\
QT_FOR_EACH_STATIC_WIDGETS_CLASS(F)\

// 注册基本类型
#define QT_FOR_EACH_STATIC_PRIMITIVE_TYPE(F)\
F(Void, 43, void) \
F(Bool, 1, bool) \
F(Int, 2, int) \
F(UInt, 3, uint) \
F(LongLong, 4, qlonglong) \
F(ULongLong, 5, qulonglong) \
F(Double, 6, double) \
F(Long, 32, long) \
F(Short, 33, short) \
F(Char, 34, char) \
F(ULong, 35, ulong) \
F(UShort, 36, ushort) \
F(UChar, 37, uchar) \
F(Float, 38, float) \
F(SChar, 40, signed char) \
F(Nullptr, 51, std::nullptr_t) \
F(QCborSimpleType, 52, QCborSimpleType) \

// 注册基本指针类型
#define QT_FOR_EACH_STATIC_PRIMITIVE_POINTER(F)\
F(VoidStar, 31, void*) \

// 注册核心类
#define QT_FOR_EACH_STATIC_CORE_CLASS(F)\
F(QChar, 7, QChar) \
F(QString, 10, QString) \
F(QStringList, 11, QStringList) \
F(QByteArray, 12, QByteArray) \
F(QBitArray, 13, QBitArray) \
F(QDate, 14, QDate) \
F(QTime, 15, QTime) \
F(QDateTime, 16, QDateTime) \
F(QUrl, 17, QUrl) \
F(QLocale, 18, QLocale) \
F(QRect, 19, QRect) \
F(QRectF, 20, QRectF) \
F(QSize, 21, QSize) \
F(QSizeF, 22, QSizeF) \
F(QLine, 23, QLine) \
F(QLineF, 24, QLineF) \
F(QPoint, 25, QPoint) \
F(QPointF, 26, QPointF) \
F(QRegExp, 27, QRegExp) \
F(QEasingCurve, 29, QEasingCurve) \
F(QUuid, 30, QUuid) \
F(QVariant, 41, QVariant) \
F(QRegularExpression, 44, QRegularExpression) \
F(QJsonValue, 45, QJsonValue) \
F(QJsonObject, 46, QJsonObject) \
F(QJsonArray, 47, QJsonArray) \
F(QJsonDocument, 48, QJsonDocument) \
F(QCborValue, 53, QCborValue) \
F(QCborArray, 54, QCborArray) \
F(QCborMap, 55, QCborMap) \
QT_FOR_EACH_STATIC_ITEMMODEL_CLASS(F)

// 注册核心指针类
#define QT_FOR_EACH_STATIC_CORE_POINTER(F)\
F(QObjectStar, 39, QObject*)

#define QT_FOR_EACH_STATIC_CORE_TEMPLATE(F)\
F(QVariantMap, 8, QVariantMap) \
F(QVariantList, 9, QVariantList) \
F(QVariantHash, 28, QVariantHash) \
F(QByteArrayList, 49, QByteArrayList) \

#define QT_FOR_EACH_STATIC_GUI_CLASS(F)\
F(QFont, 64, QFont) \
F(QPixmap, 65, QPixmap) \
F(QBrush, 66, QBrush) \
F(QColor, 67, QColor) \
F(QPalette, 68, QPalette) \
F(QIcon, 69, QIcon) \
F(QImage, 70, QImage) \
F(QPolygon, 71, QPolygon) \
F(QRegion, 72, QRegion) \
F(QBitmap, 73, QBitmap) \
F(QCursor, 74, QCursor) \
F(QKeySequence, 75, QKeySequence) \
F(QPen, 76, QPen) \
F(QTextLength, 77, QTextLength) \
F(QTextFormat, 78, QTextFormat) \
F(QMatrix, 79, QMatrix) \
F(QTransform, 80, QTransform) \
F(QMatrix4x4, 81, QMatrix4x4) \
F(QVector2D, 82, QVector2D) \
F(QVector3D, 83, QVector3D) \
F(QVector4D, 84, QVector4D) \
F(QQuaternion, 85, QQuaternion) \
F(QPolygonF, 86, QPolygonF) \

#define QT_FOR_EACH_STATIC_WIDGETS_CLASS(F)\
F(QSizePolicy, 121, QSizePolicy) \

上述宏扩展开如:

QT_FOR_EACH_STATIC_TYPE(QT_ADD_STATIC_METATYPE) 
// 扩展QT_FOR_EACH_STATIC_TYPE

#define QT_ADD_STATIC_METATYPE(MetaTypeName, MetaTypeId, RealName) \
{ #RealName, sizeof(#RealName) - 1, MetaTypeId },

// QT_FOR_EACH_STATIC_TYPE 部分内容为
F(Void, 43, void) \
F(Bool, 1, bool) \
F(UInt, 3, uint) \
F(ULong, 35, ulong) \
F(UShort, 36, ushort) \

// 扩展后实际内容为:
{ "void", sizeof("void") - 1, 43},
{ "bool", sizeof("bool") - 1, 1},
{ "uint", sizeof("uint") - 1, 3},
{ "ulong", sizeof("ulong") - 1, 35},
{ "ushort", sizeof("ushort") - 1, 36},


// ========================================================================

QT_FOR_EACH_STATIC_ALIAS_TYPE(QT_ADD_STATIC_METATYPE_ALIASES_ITER)

#define QT_ADD_STATIC_METATYPE_ALIASES_ITER(MetaTypeName, MetaTypeId, AliasingName, RealNameStr) \
{ RealNameStr, sizeof(RealNameStr) - 1, QMetaType::MetaTypeName },

// QT_FOR_EACH_STATIC_ALIAS_TYPE 部分内容为
F(ULong, -1, ulong, "unsigned long") \
F(UInt, -1, uint, "unsigned int") \
F(UShort, -1, ushort, "unsigned short") \

// 扩展后实际内容为:
{ "unsigned long", sizeof("unsigned long") - 1, 35},
{ "unsigned int", sizeof("unsigned int") - 1, 3},
{ "unsigned short", sizeof("unsigned short") - 1, 36},

// 备注:QMetaType::UInt 值正为3,由qt系统定义好了

接下来看用户注册变量customTypes():

Q_GLOBAL_STATIC(QVector<QCustomTypeInfo>, customTypes)

#define Q_GLOBAL_STATIC(TYPE, NAME) \
Q_GLOBAL_STATIC_WITH_ARGS(TYPE, NAME, ())

#define Q_GLOBAL_STATIC_WITH_ARGS(TYPE, NAME, ARGS) \
namespace { namespace Q_QGS_ ## NAME { \
typedef TYPE Type; \
QBasicAtomicInt guard = Q_BASIC_ATOMIC_INITIALIZER(QtGlobalStatic::Uninitialized); \
Q_GLOBAL_STATIC_INTERNAL(ARGS) \
} } \
static QGlobalStatic<TYPE, \
Q_QGS_ ## NAME::innerFunction, \
Q_QGS_ ## NAME::guard> NAME;


#define Q_GLOBAL_STATIC_INTERNAL(ARGS) \
Q_GLOBAL_STATIC_INTERNAL_DECORATION Type *innerFunction() \
{ \
struct HolderBase { \
~HolderBase() Q_DECL_NOTHROW \
{ if (guard.load() == QtGlobalStatic::Initialized) \
guard.store(QtGlobalStatic::Destroyed); } \
}; \
static struct Holder : public HolderBase { \
Type value; \
Holder() \
Q_DECL_NOEXCEPT_EXPR(noexcept(Type ARGS)) \
: value ARGS \
{ guard.store(QtGlobalStatic::Initialized); } \
} holder; \
return &holder.value; \
}

template <typename T, T *(&innerFunction)(), QBasicAtomicInt &guard>
struct QGlobalStatic
{
typedef T Type;

bool isDestroyed() const { return guard.load() <= QtGlobalStatic::Destroyed; }
bool exists() const { return guard.load() == QtGlobalStatic::Initialized; }
operator Type *() { if (isDestroyed()) return 0; return innerFunction(); }
Type *operator()() { if (isDestroyed()) return 0; return innerFunction(); }
Type *operator->()
{
Q_ASSERT_X(!isDestroyed(), "Q_GLOBAL_STATIC", "The global static was used after being destroyed");
return innerFunction();
}
Type &operator*()
{
Q_ASSERT_X(!isDestroyed(), "Q_GLOBAL_STATIC", "The global static was used after being destroyed");
return *innerFunction();
}
};

// 其展开为:

namespace {
namespace Q_QGS_customTypes {
typedef QVector<QCustomTypeInfo> Type;
QBasicAtomicInt guard = Q_BASIC_ATOMIC_INITIALIZER(QtGlobalStatic::Uninitialized);
QVector<QCustomTypeInfo> *innerFunction() {
...
static struct Holder : public HolderBase {
QVector<QCustomTypeInfo> value;
...
} holder;
return &holder.value;
}
}
}
static QGlobalStatic<QVector<QCustomTypeInfo>, Q_QGS_customTypes::innerFunction,
Q_QGS_customTypes::guard>customTypes

从上可知QVector<QCustomTypeInfo> *ct = customTypes();由于QGlobalStatic中对()进行了重载,所以其相当于调用:

QVector<QCustomTypeInfo> *ct = customTypes();

// 相当于调用QGlobalStatic中operator()重载方法,而innerFunction()在构造时传入,
// 其值为Q_QGS_customTypes 中innerFunction函数,其定义了静态的持有变量holder
struct QGlobalStatic
{
QVector<QCustomTypeInfo>*operator()() { if (isDestroyed()) return 0; return innerFunction(); }
};

namespace {
namespace Q_QGS_customTypes {
QVector<QCustomTypeInfo> *innerFunction() {
...
static struct Holder : public HolderBase {
QVector<QCustomTypeInfo> value;
...
} holder;
return &holder.value;
}
}
}

小结

class test : public QObject {
Q_OBJECT
public:
explicit test(QObject *parent = nullptr);
QString name;
}

class T1 {
public:
QString name;
};

class T2 {
public:
QString name;
};
Q_DECLARE_METATYPE(T2)
//Q_DECLARE_METATYPE(T2*)


void main() {
int typeId = qRegisterMetaType<test *>();
// qRegisterMetaType<test>(); // 编译不过,QObject及其子类无默认的复制函数
// qRegisterMetaType<test>("test"); // 编译不过,QObject及其子类无默认的复制函数
//int typeId4 = qRegisterMetaType<T2 *>(); // 编译不过,未声明Q_DECLARE_METATYPE(T2*)
int typeId5 = qRegisterMetaType<T2>();
int typeId2 = qRegisterMetaType<T1 *>("T1");
int typeId22 = qRegisterMetaType<T1 *>("T1*");
int typeId3 = qRegisterMetaType<T1>("T1"); // 与 typeId2 相同,说明与类型无关,与名字相关
int typeId33 = qRegisterMetaType<T1>("T1 *"); // 与 typeId22 相同,说明与类型无关,与名字相关
}

qRegisterMetaType<T>():

  • 可以注册QObject的子类指针(test继承QObject),qRegisterMetaType<test *>();
  • 不能注册QObject的子类本身(test继承QObject),qRegisterMetaType<test>()无法完成注册,因为无默认的构造、复制、析构函数。(信号与槽无法传递参数)
  • 可以注册由Q_DECLARE_METATYPE声明结构体、类

  int qRegisterMetaType(const char *typeName):

  • 可以注册有默认的构造、复制、析构函数的结构体或类
  • 返回的注册id只与typeName相关


八、信号与槽

​Qt高级——Qt信号槽机制源码解析【附源码】_天山老妖S_51CTO博客​

1、连接函数connect

connect其中一个实现为:

template <typename Func1, typename Func2>
static inline typename std::enable_if<QtPrivate::FunctionPointer<Func2>::ArgumentCount == -1, QMetaObject::Connection>::type
connect(const typename QtPrivate::FunctionPointer<Func1>::Object *sender, Func1 signal, const QObject *context, Func2 slot,
Qt::ConnectionType type = Qt::AutoConnection)
{
typedef QtPrivate::FunctionPointer<Func1> SignalType;
const int FunctorArgumentCount = QtPrivate::ComputeFunctorArgumentCount<Func2 , typename SignalType::Arguments>::Value;

const int SlotArgumentCount = (FunctorArgumentCount >= 0) ? FunctorArgumentCount : 0;
typedef typename QtPrivate::FunctorReturnType<Func2, typename QtPrivate::List_Left<typename SignalType::Arguments, SlotArgumentCount>::Value>::Value SlotReturnType;


const int *types = nullptr;
if (type == Qt::QueuedConnection || type == Qt::BlockingQueuedConnection)
types = QtPrivate::ConnectionTypes<typename SignalType::Arguments>::types();

return connectImpl(sender, reinterpret_cast<void **>(&signal), context, nullptr,
new QtPrivate::QFunctorSlotObject<Func2, SlotArgumentCount,
typename QtPrivate::List_Left<typename SignalType::Arguments, SlotArgumentCount>::Value,
typename SignalType::ReturnType>(std::move(slot)),
type, types, &SignalType::Object::staticMetaObject);
}

connect是一个模板,其展开并精简后为:

QMetaObject::Connection QObject::connect(const QObject *sender, PointerToMemberFunction signal, const QObject *receiver, PointerToMemberFunction method, Qt::ConnectionType type = Qt::AutoConnection) {
...
return connectImpl(sender, reinterpret_cast<void **>(&signal), context, nullptr,
new QtPrivate::QFunctorSlotObject<Func2, SlotArgumentCount,
typename QtPrivate::List_Left<typename SignalType::Arguments, SlotArgumentCount>::Value,
typename SignalType::ReturnType>(std::move(slot)),
type, types, &SignalType::Object::staticMetaObject);
}

接下来看函数connectImpl:

QMetaObject::Connection QObject::connectImpl(const QObject *sender, void **signal,
const QObject *receiver, void **slot,
QtPrivate::QSlotObjectBase *slotObj, Qt::ConnectionType type,
const int *types, const QMetaObject *senderMetaObject)
{
if (!signal) {
qWarning("QObject::connect: invalid null parameter");
if (slotObj)
slotObj->destroyIfLastRef();
return QMetaObject::Connection();
}

int signal_index = -1;
void *args[] = { &signal_index, signal };
// 通过信号函数找到其在moc中的序号,
// senderMetaObject->static_metacall(QMetaObject::IndexOfMethod, 0, args)
// 最终会调用moc文件中的qt_static_metacall方法里的IndexOfMethod情况
// {
// using _t = int (test::*)(QString * );
// if (*reinterpret_cast<_t *>(_a[1]) == static_cast<_t>(&test::sgn4)) {
// *result = 3;
// return;
// }
// }
// {
// using _t = int (test::*)(QString , QString , int );
// if (*reinterpret_cast<_t *>(_a[1]) == static_cast<_t>(&test::sgn5)) {
// *result = 4;
// return;
// }
// }
for (; senderMetaObject && signal_index < 0; senderMetaObject = senderMetaObject->superClass()) {
senderMetaObject->static_metacall(QMetaObject::IndexOfMethod, 0, args);
if (signal_index >= 0 && signal_index < QMetaObjectPrivate::get(senderMetaObject)->signalCount)
break;
}
if (!senderMetaObject) {
qWarning("QObject::connect: signal not found in %s", sender->metaObject()->className());
slotObj->destroyIfLastRef();
return QMetaObject::Connection(0);
}
// 把当前类中的信号顺序转换成全局中的信号,其转换方法为依次叠加父类中的信号个数
signal_index += QMetaObjectPrivate::signalOffset(senderMetaObject);
// 进一步处理信号与槽的连接
return QObjectPrivate::connectImpl(sender, signal_index, receiver, slot, slotObj, type, types, senderMetaObject);
}

int QMetaObjectPrivate::signalOffset(const QMetaObject *m)
{
Q_ASSERT(m != 0);
int offset = 0;
// 依次叠加父类中的信号个数,最后返回总父类们信号总个数
for (m = m->d.superdata; m; m = m->d.superdata)
offset += priv(m->d.data)->signalCount;
return offset;
}

接下来我们看进一步处理信号与槽连接的函数connectImpl,其参数为(sender, signal_index, receiver, slot, slotObj, type, types, senderMetaObject):

QMetaObject::Connection QObjectPrivate::connectImpl(const QObject *sender, int signal_index,
const QObject *receiver, void **slot,
QtPrivate::QSlotObjectBase *slotObj, Qt::ConnectionType type,
const int *types, const QMetaObject *senderMetaObject)
{
if (!sender || !receiver || !slotObj || !senderMetaObject) {
const char *senderString = sender ? sender->metaObject()->className()
: senderMetaObject ? senderMetaObject->className()
: "Unknown";
const char *receiverString = receiver ? receiver->metaObject()->className()
: "Unknown";
qWarning("QObject::connect(%s, %s): invalid null parameter", senderString, receiverString);
if (slotObj)
slotObj->destroyIfLastRef();
return QMetaObject::Connection();
}

// 发送者
QObject *s = const_cast<QObject *>(sender);
// 信号接收者,即槽函数所在的对象
QObject *r = const_cast<QObject *>(receiver);

QOrderedMutexLocker locker(signalSlotLock(sender),
signalSlotLock(receiver));

// 处理唯一连接的情况
if (type & Qt::UniqueConnection && slot) {
QObjectConnectionListVector *connectionLists = QObjectPrivate::get(s)->connectionLists;
if (connectionLists && connectionLists->count() > signal_index) {
const QObjectPrivate::Connection *c2 =
(*connectionLists)[signal_index].first;

while (c2) {
if (c2->receiver == receiver && c2->isSlotObject && c2->slotObj->compare(slot)) {
slotObj->destroyIfLastRef();
return QMetaObject::Connection();
}
c2 = c2->nextConnectionList;
}
}
type = static_cast<Qt::ConnectionType>(type ^ Qt::UniqueConnection);
}

QScopedPointer<QObjectPrivate::Connection> c(new QObjectPrivate::Connection);
c->sender = s;
c->signal_index = signal_index;
c->receiver = r;
c->slotObj = slotObj;
c->connectionType = type;
c->isSlotObject = true;
if (types) {
c->argumentTypes.store(types);
c->ownArgumentTypes = false;
}

// 新建一个Connection,并添加到QObjectPrivate::connectionLists中,
// connectionLists是一个QVector,以信号顺序为索引
QObjectPrivate::get(s)->addConnection(signal_index, c.data());
QMetaObject::Connection ret(c.take());
locker.unlock();

QMetaMethod method = QMetaObjectPrivate::signal(senderMetaObject, signal_index);
Q_ASSERT(method.isValid());
s->connectNotify(method);

return ret;
}

void QObjectPrivate::addConnection(int signal, Connection *c)
{
Q_ASSERT(c->sender == q_ptr);
// connectionLists类型为QObjectConnectionListVector,
// 其继承QVector<QObjectPrivate::ConnectionList>
// 其以信号顺序为索引,没有则创建,不够则调整数组大小
// struct ConnectionList {
// ConnectionList() : first(nullptr), last(nullptr) {}
// Connection *first;
// Connection *last;
// };
if (!connectionLists)
connectionLists = new QObjectConnectionListVector();
if (signal >= connectionLists->count())
connectionLists->resize(signal + 1);

// ConnectionList中first指向第一个,last指向最后一个,后面添加的都放在末尾
ConnectionList &connectionList = (*connectionLists)[signal];
if (connectionList.last) {
connectionList.last->nextConnectionList = c;
} else {
connectionList.first = c;
}
connectionList.last = c;

// 清除失效的连接
cleanConnectionLists();

// 接收者的senders指向最后一个与其连接的信号的Connection
// Connection 的 prev 指向接收者的senders的地址,next指向senders本身,
// 而接收者的senders始终指向最后一个与其相连的信号的Connection
// 所以当信号连接槽时,若槽上已经有别的信号与其连接,则当前Connection的pre指向槽对象senders的地址,
// 其next指向上一个与槽连接的信号Connection ,
// 并且把上一个与槽连接的信号Connection的pre由指向
// 槽对象senders的地址改成指向其本身
c->prev = &(QObjectPrivate::get(c->receiver)->senders);
c->next = *c->prev;
*c->prev = c;
if (c->next)
c->next->prev = &c->next;

if (signal < 0) {
connectedSignals[0].store(~0);
connectedSignals[1].store(~0);
} else if (signal < (int)sizeof(connectedSignals) * 8) {
connectedSignals[signal >> 5].store(connectedSignals[signal >> 5].load() | (1 << (signal & 0x1f)));
}
}

2、信号发送

void t5() {
int r = emit sgn5("name", "sex", 18);
qDebug() << "t5 return " << r;
}

// SIGNAL 4
int test::sgn5(QString _t1, QString _t2, int _t3)
{
int _t0{};
void *_a[] = { const_cast<void*>(reinterpret_cast<const void*>(&_t0)), const_cast<void*>(reinterpret_cast<const void*>(&_t1)), const_cast<void*>(reinterpret_cast<const void*>(&_t2)), const_cast<void*>(reinterpret_cast<const void*>(&_t3)) };
QMetaObject::activate(this, &staticMetaObject, 4, _a);
return _t0;
}

void QMetaObject::activate(QObject *sender, const QMetaObject *m, int local_signal_index,
void **argv)
{
// signalOffset找到全局的信号序号
activate(sender, QMetaObjectPrivate::signalOffset(m), local_signal_index, argv);
}

void QMetaObject::activate(QObject *sender, int signalOffset, int local_signal_index, void **argv)
{
int signal_index = signalOffset + local_signal_index;

if (sender->d_func()->blockSig)
return;

Q_TRACE_SCOPE(QMetaObject_activate, sender, signal_index);

if (sender->d_func()->isDeclarativeSignalConnected(signal_index)
&& QAbstractDeclarativeData::signalEmitted) {
Q_TRACE_SCOPE(QMetaObject_activate_declarative_signal, sender, signal_index);
QAbstractDeclarativeData::signalEmitted(sender->d_func()->declarativeData, sender,
signal_index, argv);
}

if (!sender->d_func()->isSignalConnected(signal_index, /*checkDeclarative =*/ false)
&& !qt_signal_spy_callback_set.signal_begin_callback
&& !qt_signal_spy_callback_set.signal_end_callback) {
// The possible declarative connection is done, and nothing else is connected, so:
return;
}

void *empty_argv[] = { 0 };
if (qt_signal_spy_callback_set.signal_begin_callback != 0) {
qt_signal_spy_callback_set.signal_begin_callback(sender, signal_index,
argv ? argv : empty_argv);
}

{
QMutexLocker locker(signalSlotLock(sender));
struct ConnectionListsRef {
QObjectConnectionListVector *connectionLists;
ConnectionListsRef(QObjectConnectionListVector *connectionLists) : connectionLists(connectionLists)
{
if (connectionLists)
++connectionLists->inUse;
}
~ConnectionListsRef()
{
if (!connectionLists)
return;

--connectionLists->inUse;
Q_ASSERT(connectionLists->inUse >= 0);
if (connectionLists->orphaned) {
if (!connectionLists->inUse)
delete connectionLists;
}
}

QObjectConnectionListVector *operator->() const { return connectionLists; }
};
ConnectionListsRef connectionLists = sender->d_func()->connectionLists;
if (!connectionLists.connectionLists) {
locker.unlock();
if (qt_signal_spy_callback_set.signal_end_callback != 0)
qt_signal_spy_callback_set.signal_end_callback(sender, signal_index);
return;
}

const QObjectPrivate::ConnectionList *list;
if (signal_index < connectionLists->count())
list = &connectionLists->at(signal_index);
else
list = &connectionLists->allsignals;

Qt::HANDLE currentThreadId = QThread::currentThreadId();

do {
QObjectPrivate::Connection *c = list->first;
if (!c) continue;
// We need to check against last here to ensure that signals added
// during the signal emission are not emitted in this emission.
QObjectPrivate::Connection *last = list->last;

// 依次调用与信号连接的槽函数
do {
if (!c->receiver)
continue;

QObject * const receiver = c->receiver;
const bool receiverInSameThread = currentThreadId == receiver->d_func()->threadData->threadId.load();

// determine if this connection should be sent immediately or
// put into the event queue
// 判断connection 是否立即执行还是放入队列中
if ((c->connectionType == Qt::AutoConnection && !receiverInSameThread)
|| (c->connectionType == Qt::QueuedConnection)) {
// 放入队列中
queued_activate(sender, signal_index, c, argv ? argv : empty_argv, locker);
continue;
#if QT_CONFIG(thread)
} else if (c->connectionType == Qt::BlockingQueuedConnection) {
// 放入阻塞队列中
if (receiverInSameThread) {
qWarning("Qt: Dead lock detected while activating a BlockingQueuedConnection: "
"Sender is %s(%p), receiver is %s(%p)",
sender->metaObject()->className(), sender,
receiver->metaObject()->className(), receiver);
}
QSemaphore semaphore;
QMetaCallEvent *ev = c->isSlotObject ?
new QMetaCallEvent(c->slotObj, sender, signal_index, 0, 0, argv ? argv : empty_argv, &semaphore) :
new QMetaCallEvent(c->method_offset, c->method_relative, c->callFunction, sender, signal_index, 0, 0, argv ? argv : empty_argv, &semaphore);
QCoreApplication::postEvent(receiver, ev);
locker.unlock();
semaphore.acquire();
locker.relock();
continue;
#endif
}

QConnectionSenderSwitcher sw;

if (receiverInSameThread) {
sw.switchSender(receiver, sender, signal_index);
}
// 连接时采用函数指针形式进入此入口,如:connect(tObj, &test::sgn3, this, &MainWindow::slt3);
if (c->isSlotObject) {
c->slotObj->ref();
QScopedPointer<QtPrivate::QSlotObjectBase, QSlotObjectBaseDeleter> obj(c->slotObj);
locker.unlock();

{
Q_TRACE_SCOPE(QMetaObject_activate_slot_functor, obj.data());
obj->call(receiver, argv ? argv : empty_argv);
}

// Make sure the slot object gets destroyed before the mutex is locked again, as the
// destructor of the slot object might also lock a mutex from the signalSlotLock() mutex pool,
// and that would deadlock if the pool happens to return the same mutex.
obj.reset();

locker.relock();
} else if (c->callFunction && c->method_offset <= receiver->metaObject()->methodOffset()) {
// 连接时采用函数参数字符串的形式,则进入此分支,如:connect(tObj, SIGNAL(sgn4(QString *)), this, SLOT(slt4(QString*)));
//we compare the vtable to make sure we are not in the destructor of the object.
const int methodIndex = c->method();
const int method_relative = c->method_relative;
const auto callFunction = c->callFunction;
locker.unlock();
if (qt_signal_spy_callback_set.slot_begin_callback != 0)
qt_signal_spy_callback_set.slot_begin_callback(receiver, methodIndex, argv ? argv : empty_argv);

{
Q_TRACE_SCOPE(QMetaObject_activate_slot, receiver, methodIndex);
callFunction(receiver, QMetaObject::InvokeMetaMethod, method_relative, argv ? argv : empty_argv);
}

if (qt_signal_spy_callback_set.slot_end_callback != 0)
qt_signal_spy_callback_set.slot_end_callback(receiver, methodIndex);
locker.relock();
} else {
const int method = c->method_relative + c->method_offset;
locker.unlock();

if (qt_signal_spy_callback_set.slot_begin_callback != 0) {
qt_signal_spy_callback_set.slot_begin_callback(receiver,
method,
argv ? argv : empty_argv);
}

{
Q_TRACE_SCOPE(QMetaObject_activate_slot, receiver, method);
metacall(receiver, QMetaObject::InvokeMetaMethod, method, argv ? argv : empty_argv);
}

if (qt_signal_spy_callback_set.slot_end_callback != 0)
qt_signal_spy_callback_set.slot_end_callback(receiver, method);

locker.relock();
}

if (connectionLists->orphaned)
break;
} while (c != last && (c = c->nextConnectionList) != 0);

if (connectionLists->orphaned)
break;
} while (list != &connectionLists->allsignals &&
//start over for all signals;
((list = &connectionLists->allsignals), true));

}

if (qt_signal_spy_callback_set.signal_end_callback != 0)
qt_signal_spy_callback_set.signal_end_callback(sender, signal_index);
}

2.1 直连Qt::DirectConnection

c->isSlotObject:obj->call(receiver, argv ? argv : empty_argv); 因为直接调用,argv指向的参数都存在,所以不能拷贝参数。连接采用指针时,isSlotObject为真,如:connect(tObj, &test::sgn3, this, &MainWindow::slt3),否则以字符串形式连接为false,如:connect(tObj, SIGNAL(sgn4(QString *)), this, SLOT(slt4(QString*)));,此时其调用为

else if (c->callFunction && c->method_offset <= receiver->metaObject()->methodOffset()) {
//we compare the vtable to make sure we are not in the destructor of the object.
const int methodIndex = c->method();
const int method_relative = c->method_relative;
const auto callFunction = c->callFunction;
locker.unlock();
if (qt_signal_spy_callback_set.slot_begin_callback != 0)
qt_signal_spy_callback_set.slot_begin_callback(receiver, methodIndex, argv ? argv : empty_argv);

{
Q_TRACE_SCOPE(QMetaObject_activate_slot, receiver, methodIndex);
callFunction(receiver, QMetaObject::InvokeMetaMethod, method_relative, argv ? argv : empty_argv);
}

if (qt_signal_spy_callback_set.slot_end_callback != 0)
qt_signal_spy_callback_set.slot_end_callback(receiver, methodIndex);
locker.relock();
}

callFunction指向:槽函数所在对象的MainWindow::qt_static_metacall方法

2.2 队列Qt::QueuedConnection

static void queued_activate(QObject *sender, int signal, QObjectPrivate::Connection *c, void **argv,
QMutexLocker &locker)
{
// 获取参数类型,这里参数为(QString, QString, int),argumentTypes 对应的值为10,10,2
// 为QMetaType::Type中的值,QMetaType::QString为10,QMetaType::Int为2
const int *argumentTypes = c->argumentTypes.load();
if (!argumentTypes) {
QMetaMethod m = QMetaObjectPrivate::signal(sender->metaObject(), signal);
argumentTypes = queuedConnectionTypes(m.parameterTypes());
if (!argumentTypes) // cannot queue arguments
argumentTypes = &DIRECT_CONNECTION_ONLY;
if (!c->argumentTypes.testAndSetOrdered(0, argumentTypes)) {
if (argumentTypes != &DIRECT_CONNECTION_ONLY)
delete [] argumentTypes;
argumentTypes = c->argumentTypes.load();
}
}
if (argumentTypes == &DIRECT_CONNECTION_ONLY) // cannot activate
return;
int nargs = 1; // include return type
while (argumentTypes[nargs-1])
++nargs;
// 动态创建返回值和参数的类型空间
int *types = (int *) malloc(nargs*sizeof(int));
Q_CHECK_PTR(types);
// 动态创建返回值和参数的值空间
void **args = (void **) malloc(nargs*sizeof(void *));
Q_CHECK_PTR(args);
types[0] = 0; // return type
args[0] = 0; // return value

if (nargs > 1) {
// 填入参数类型, QMetaType::Type
for (int n = 1; n < nargs; ++n)
types[n] = argumentTypes[n-1];

locker.unlock();
// 填入参数的值, 即动态复制参数,args中保存了动态复制的参数地址
// 如QString参数, 先分配存储空间,然后复制QString,最后args[0]指向这个空间
for (int n = 1; n < nargs; ++n)
args[n] = QMetaType::create(types[n], argv[n]);
locker.relock();

if (!c->receiver) {
locker.unlock();
// we have been disconnected while the mutex was unlocked
for (int n = 1; n < nargs; ++n)
QMetaType::destroy(types[n], args[n]);
free(types);
free(args);
locker.relock();
return;
}
}

QMetaCallEvent *ev = c->isSlotObject ?
new QMetaCallEvent(c->slotObj, sender, signal, nargs, types, args) :
new QMetaCallEvent(c->method_offset, c->method_relative, c->callFunction, sender, signal, nargs, types, args);
// 发送事件到队列中
QCoreApplication::postEvent(c->receiver, ev);
}

构建好QMetaCallEvent事件后,通过postEvent进行发送,后面队列将处理这个消息,其调用堆栈为:

从源码角度分析Qt元对象系统_1024程序员节

bool QObject::event(QEvent *e) {
...
case QEvent::MetaCall:
{
QMetaCallEvent *mce = static_cast<QMetaCallEvent*>(e);

QConnectionSenderSwitcher sw(this, const_cast<QObject*>(mce->sender()), mce->signalId());

mce->placeMetaCall(this);
break;
}
...
}

void QMetaCallEvent::placeMetaCall(QObject *object)
{
if (slotObj_) {
// args_ 为刚才拷贝的参数值指针数组
slotObj_->call(object, args_);
} else if (callFunction_ && method_offset_ <= object->metaObject()->methodOffset()) {
callFunction_(object, QMetaObject::InvokeMetaMethod, method_relative_, args_);
} else {
QMetaObject::metacall(object, QMetaObject::InvokeMetaMethod, method_offset_ + method_relative_, args_);
}
}

template<typename Function, int N> struct Functor
{
template <typename SignalArgs, typename R>
static void call(Function &f, void *, void **arg) {
FunctorCall<typename Indexes<N>::Value, SignalArgs, R, Function>::call(f, arg);
}
};

template <typename, typename, typename, typename> struct FunctorCall;
template <int... II, typename... SignalArgs, typename R, typename Function>
struct FunctorCall<IndexesList<II...>, List<SignalArgs...>, R, Function> {
static void call(Function &f, void **arg) {
f((*reinterpret_cast<typename RemoveRef<SignalArgs>::Type *>(arg[II+1]))...), ApplyReturnValue<R>(arg[0]);
}
};

connect(tObj, &test::sgn5, this, [](QString _t1, QString t2, int age) {
qDebug() << "Recv sgn5 in myTest";
qDebug() << "Recv sgn5 in myTest....." << _t1 << t2 << age;
return 10;
}, Qt::QueuedConnection);

最后经过一系列调用,会调用与信号连接的槽函数

2.3 阻塞队列Qt::BlockingQueuedConnection

if (receiverInSameThread) {
qWarning("Qt: Dead lock detected while activating a BlockingQueuedConnection: "
"Sender is %s(%p), receiver is %s(%p)",
sender->metaObject()->className(), sender,
receiver->metaObject()->className(), receiver);
}
QSemaphore semaphore;
QMetaCallEvent *ev = c->isSlotObject ?
new QMetaCallEvent(c->slotObj, sender, signal_index, 0, 0, argv ? argv : empty_argv, &semaphore) :
new QMetaCallEvent(c->method_offset, c->method_relative, c->callFunction, sender, signal_index, 0, 0, argv ? argv : empty_argv, &semaphore);
QCoreApplication::postEvent(receiver, ev);
locker.unlock();
semaphore.acquire();
locker.relock();
continue;

阻塞队列不能在发送者与接收者不能在同一个线程中。因为是阻塞的,所以参数也无需拷贝,直接发送QMetaCallEvent到队列中。


标签:return,Qt,int,角度,源码,QMetaObject,test,const,QT
From: https://blog.51cto.com/u_15930680/5991247

相关文章

  • 直播app源码,Java的输入输出
    直播app源码,Java的输入输出第一种输入方法:scanner importjava.util.Scanner;//导入java.util.ScannerpublicclassUser{  publicstaticvoidmain(String[]......
  • 成品直播源码,设置样式(字体样式、行列宽高、对齐方式、边框、填充和渐变)
    成品直播源码,设置样式(字体样式、行列宽高、对齐方式、边框、填充和渐变)1.字体样式 fromopenpyxlimportWorkbookfromopenpyxl.stylesimportFontwb=Workbook()ws......
  • 直播系统app源码,用递归实现冒泡排序
    直播系统app源码,用递归实现冒泡排序冒泡排序 publicvoidbubble(List<Integer>list){  //从后向前遍历数组  for(inti=list.size()-1;i>0;i--)......
  • QtXlsx加入-内容来源网络,方便自己查阅
    打开QXlsx源码-用qtCreat打开pro文件  注意,需要区分32位和64位    ......
  • Qt QRect 和 OpenCV cv::Rect 的区别
    1//构建一个QT的QRect对象2QRectqrect(0,0,100,100);3qDebug()<<"qrect.bottomRight:"<<qrect.bottomRight();45//构建一个opencv的cv::Rect对象6cv::Rect......
  • Qt多国语言
    ​​Qt多国语言的实现与切换(国际化)​​Qt多国语言的实现​​【大话QT之十四】QT实现多语言切换-​​用Qt5中实现多国语言支持-简书​​​​VS2017QT实现多语言国际......
  • Qt中的事件
    1、​​Qt中的事件(3)-自定义事件​​2、​​QtpostEvent​​3、​​19.QT-事件发送函数sendEvent()、postEvent()​​4、​​Qt之事件处理机制​​5、​​Qt5事件(event)机......
  • QT信号槽
    一、连接方式介绍QMetaObject::ConnectionQObject::connect(constQObject*sender,constchar*signal,constQObject*receiver,constchar*method,......
  • 在线客服系统的源码中Golang Gin框架实现IP白名单机制
    我的客服系统有一些接口是专门给内部调用的,只允许其他内部系统来调用,不允许随意访问,可以使用IP白名单机制使用Gin框架实现IP白名单机制可以使用中间件的方式实现。你......
  • 读 NebulaGraph源码 | 查询语句 LOOKUP 的一生
    本文由社区用户Milittle供稿LOOKUP是图数据库NebulaGraph的一个查询语句。它依赖索引,可以查询点或者边的信息。在本文,我将着重从源码的角度解析一下LOOKUP语句......