Qt 中 Q_OBJECT 宏及 moc_前缀文件
Q_OBJECT 宏
元对象系统 (Meta-Object System)
- Qt框架在C++基础上增加了元对象系统 (Meta-Object-System)
- Qt中所有类全部继承自QObject类,这是使用元对象系统的前提
- Qt中信号-槽机制是元对象系统提供的最重要内容,本质上是基于C++中函数、函数指针、回调函数等一系列语法构成,其实现与
Q_OBJECT
宏有关
了解 Q_OBJECT 宏
- 启用 Meta-Object-System 一系列功能,如信号-槽机制
Q_OBJECT
宏会对Qt中的类进行标识,以便被Qt提供的moc预编译器识别- moc预编译器将头文件中的Q_OBJECT 宏展开,若类的声明及定义在.cpp文件内,则预编译器不会产生相对应的moc_xx.cpp文件
Q_OBJECT
宏不应当随意去除,不仅信号-槽机制依赖于该宏,其他一些例如国际化机制、不基于 C++ RTTI 的反射等能力也依赖于该宏
展开 Q_OBJECT 宏
#define Q_OBJECT \
public: \
QT_WARNING_PUSH \
Q_OBJECT_NO_OVERRIDE_WARNING \
static const QMetaObject staticMetaObject; \
virtual const QMetaObject *metaObject() const; \
virtual void *qt_metacast(const char *); \
virtual int qt_metacall(QMetaObject::Call, int, void **); \
QT_TR_FUNCTIONS \
private: \
Q_OBJECT_NO_ATTRIBUTES_WARNING \
Q_DECL_HIDDEN_STATIC_METACALL static void qt_static_metacall(QObject *, QMetaObject::Call, int, void **); \
QT_WARNING_POP \
struct QPrivateSignal {}; \
QT_ANNOTATE_CLASS(qt_qobject, "")
- 由此不难看出,Qt源码中
Q_OBJECT
宏展开后,主要内容为 “元对象系统” 的一部分函数 (如信号-槽机制) 声明,但其实现并非在qobject.cpp文件中,而是在moc_qobject.cpp文件中 static const QMetaObject staticMetaObject;
保存该类的元对象系统信息,为类的所有对象共享virtual const QMetaObject *metaObject() const;
这个函数通常情况下会返回类的静态元对象staticMetaObject的地址,如果在 QML 程序中,会返回非静态元对象virtual int qt_metacall(QMetaObject::Call, int, void **);
这个函数负责槽函数的调用和属性系统的读写,内部会调用下方函数qt_static_metacall(QObject *, QMetaObject::Call, int, void **);
这个函数是槽函数调用机制的实现QT_TR_FUNCTIONS
这个宏负责实现翻译国际化字符串,展开如下
# define QT_TR_FUNCTIONS \
static inline QString tr(const char *s, const char *c = nullptr, int n = -1) \
{ return staticMetaObject.tr(s, c, n); } \
QT_DEPRECATED static inline QString trUtf8(const char *s, const char *c = nullptr, int n = -1) \
{ return staticMetaObject.tr(s, c, n); }
MOC 预编译器
MOC (Meta-Object Compiler)
- moc 即元对象系统的预编译器
- Qt 将源代码交给标准 C++ 编译器 (如 gcc) 之前,需要事先将这些扩展的语法去除掉。完成这一操作的就是 moc。预处理器执行之后,
Q_OBJECT
宏将不存在 - moc 读取一个C++头文件,如果它找到包含
Q_OBJECT
宏的一个或多个类声明,则会生成一个包含这些类的元对象代码的C++源文件,并且以moc_作为前缀 - 信号和槽机制、运行时类型信息和动态属性系统都需要元对象代码。所以由moc生成的C++源文件必须编译并与类的实现联系起来。通常,moc无需手工调用,而是由构建系统自动调用的,因此它不需要程序员额外的工作。
前缀 moc_xx.cpp文件
- moc 预编译后产生的对应类的元对象代码C++源文件
代码示例如下
- whatismoc.h
#ifndef WHATISMOC_H
#define WHATISMOC_H
#include <QObject>
#include <QString>
#include <iostream>
class WhatIsMoc : public QObject
{
Q_OBJECT
public:
explicit WhatIsMoc(QObject *parent = nullptr);
signals:
void sigTest1(const QString& text);
void sigTest2(const QString& text, int num);
void sigTest3(const QString& text); // 不连接任何槽;
public slots:
void sltTest1(const QString& text);
void sltTest2(const QString& text, int num);
void sltTest3(const QString& text); // 不连接任何信号;
};
#endif // WHATISMOC_H
自定义WhatIsMoc类继承自QObject,并分别定义信号与槽:
信号:sigTest1、sigTest2、sigTest3
槽:sltTest1、sltTest2、sltTest3
其中:sigTest3不与任何槽连接、sltTest3不与任何信号连接
- whatismoc.cpp
#include "whatismoc.h"
WhatIsMoc::WhatIsMoc(QObject *parent) : QObject(parent)
{
connect(this, &WhatIsMoc::sigTest1, this, &WhatIsMoc::sltTest1);
connect(this, &WhatIsMoc::sigTest2, this, &WhatIsMoc::sltTest2);
}
void WhatIsMoc::sltTest1(const QString &text)
{
std::cout << "sltTest1";
}
void WhatIsMoc::sltTest2(const QString &text, int num)
{
std::cout << "sltTest2";
}
void WhatIsMoc::sltTest3(const QString &text)
{
std::cout << "sltTest3";
}
- main.cpp
#include <QCoreApplication>
#include "whatismoc.h"
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
WhatIsMoc moc;
return a.exec();
}
MakeFile文件
- 打开Qt自动生成的MakeFile文件,看到如下一行:
SOURCES = ..\WhatIsMoc\main.cpp \
..\WhatIsMoc\whatismoc.cpp debug\moc_whatismoc.cpp
- 由此可知,Qt自动生成了moc_whatismoc.cpp文件
生成的moc文件如下
- moc_whatismoc.cpp
/****************************************************************************
** Meta object code from reading C++ file 'whatismoc.h'
**
** Created by: The Qt Meta Object Compiler version 67 (Qt 5.9.9)
**
** WARNING! All changes made in this file will be lost!
*****************************************************************************/
#include "../../WhatIsMoc/whatismoc.h"
#include <QtCore/qbytearray.h>
#include <QtCore/qmetatype.h>
#if !defined(Q_MOC_OUTPUT_REVISION)
#error "The header file 'whatismoc.h' doesn't include <QObject>."
#elif Q_MOC_OUTPUT_REVISION != 67
#error "This file was generated using the moc from 5.9.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_WhatIsMoc_t {
QByteArrayData data[10];
char stringdata0[74];
};
#define QT_MOC_LITERAL(idx, ofs, len) \
Q_STATIC_BYTE_ARRAY_DATA_HEADER_INITIALIZER_WITH_OFFSET(len, \
qptrdiff(offsetof(qt_meta_stringdata_WhatIsMoc_t, stringdata0) + ofs \
- idx * sizeof(QByteArrayData)) \
)
static const qt_meta_stringdata_WhatIsMoc_t qt_meta_stringdata_WhatIsMoc = {
{
QT_MOC_LITERAL(0, 0, 9), // "WhatIsMoc"
QT_MOC_LITERAL(1, 10, 8), // "sigTest1"
QT_MOC_LITERAL(2, 19, 0), // ""
QT_MOC_LITERAL(3, 20, 4), // "text"
QT_MOC_LITERAL(4, 25, 8), // "sigTest2"
QT_MOC_LITERAL(5, 34, 3), // "num"
QT_MOC_LITERAL(6, 38, 8), // "sigTest3"
QT_MOC_LITERAL(7, 47, 8), // "sltTest1"
QT_MOC_LITERAL(8, 56, 8), // "sltTest2"
QT_MOC_LITERAL(9, 65, 8) // "sltTest3"
},
"WhatIsMoc\0sigTest1\0\0text\0sigTest2\0num\0"
"sigTest3\0sltTest1\0sltTest2\0sltTest3"
};
#undef QT_MOC_LITERAL
static const uint qt_meta_data_WhatIsMoc[] = {
// content:
7, // revision
0, // classname
0, 0, // classinfo
6, 14, // methods
0, 0, // properties
0, 0, // enums/sets
0, 0, // constructors
0, // flags
3, // signalCount
// signals: name, argc, parameters, tag, flags
1, 1, 44, 2, 0x06 /* Public */,
4, 2, 47, 2, 0x06 /* Public */,
6, 1, 52, 2, 0x06 /* Public */,
// slots: name, argc, parameters, tag, flags
7, 1, 55, 2, 0x0a /* Public */,
8, 2, 58, 2, 0x0a /* Public */,
9, 1, 63, 2, 0x0a /* Public */,
// signals: parameters
QMetaType::Void, QMetaType::QString, 3,
QMetaType::Void, QMetaType::QString, QMetaType::Int, 3, 5,
QMetaType::Void, QMetaType::QString, 3,
// slots: parameters
QMetaType::Void, QMetaType::QString, 3,
QMetaType::Void, QMetaType::QString, QMetaType::Int, 3, 5,
QMetaType::Void, QMetaType::QString, 3,
0 // eod
};
void WhatIsMoc::qt_static_metacall(QObject *_o, QMetaObject::Call _c, int _id, void **_a)
{
if (_c == QMetaObject::InvokeMetaMethod) {
WhatIsMoc *_t = static_cast<WhatIsMoc *>(_o);
Q_UNUSED(_t)
switch (_id) {
case 0: _t->sigTest1((*reinterpret_cast< const QString(*)>(_a[1]))); break;
case 1: _t->sigTest2((*reinterpret_cast< const QString(*)>(_a[1])),(*reinterpret_cast< int(*)>(_a[2]))); break;
case 2: _t->sigTest3((*reinterpret_cast< const QString(*)>(_a[1]))); break;
case 3: _t->sltTest1((*reinterpret_cast< const QString(*)>(_a[1]))); break;
case 4: _t->sltTest2((*reinterpret_cast< const QString(*)>(_a[1])),(*reinterpret_cast< int(*)>(_a[2]))); break;
case 5: _t->sltTest3((*reinterpret_cast< const QString(*)>(_a[1]))); break;
default: ;
}
} else if (_c == QMetaObject::IndexOfMethod) {
int *result = reinterpret_cast<int *>(_a[0]);
{
typedef void (WhatIsMoc::*_t)(const QString & );
if (*reinterpret_cast<_t *>(_a[1]) == static_cast<_t>(&WhatIsMoc::sigTest1)) {
*result = 0;
return;
}
}
{
typedef void (WhatIsMoc::*_t)(const QString & , int );
if (*reinterpret_cast<_t *>(_a[1]) == static_cast<_t>(&WhatIsMoc::sigTest2)) {
*result = 1;
return;
}
}
{
typedef void (WhatIsMoc::*_t)(const QString & );
if (*reinterpret_cast<_t *>(_a[1]) == static_cast<_t>(&WhatIsMoc::sigTest3)) {
*result = 2;
return;
}
}
}
}
const QMetaObject WhatIsMoc::staticMetaObject = {
{ &QObject::staticMetaObject, qt_meta_stringdata_WhatIsMoc.data,
qt_meta_data_WhatIsMoc, qt_static_metacall, nullptr, nullptr}
};
const QMetaObject *WhatIsMoc::metaObject() const
{
return QObject::d_ptr->metaObject ? QObject::d_ptr->dynamicMetaObject() : &staticMetaObject;
}
void *WhatIsMoc::qt_metacast(const char *_clname)
{
if (!_clname) return nullptr;
if (!strcmp(_clname, qt_meta_stringdata_WhatIsMoc.stringdata0))
return static_cast<void*>(this);
return QObject::qt_metacast(_clname);
}
int WhatIsMoc::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 < 6)
qt_static_metacall(this, _c, _id, _a);
_id -= 6;
} else if (_c == QMetaObject::RegisterMethodArgumentMetaType) {
if (_id < 6)
*reinterpret_cast<int*>(_a[0]) = -1;
_id -= 6;
}
return _id;
}
// SIGNAL 0
void WhatIsMoc::sigTest1(const QString & _t1)
{
void *_a[] = { nullptr, const_cast<void*>(reinterpret_cast<const void*>(&_t1)) };
QMetaObject::activate(this, &staticMetaObject, 0, _a);
}
// SIGNAL 1
void WhatIsMoc::sigTest2(const QString & _t1, int _t2)
{
void *_a[] = { nullptr, const_cast<void*>(reinterpret_cast<const void*>(&_t1)), const_cast<void*>(reinterpret_cast<const void*>(&_t2)) };
QMetaObject::activate(this, &staticMetaObject, 1, _a);
}
// SIGNAL 2
void WhatIsMoc::sigTest3(const QString & _t1)
{
void *_a[] = { nullptr, const_cast<void*>(reinterpret_cast<const void*>(&_t1)) };
QMetaObject::activate(this, &staticMetaObject, 2, _a);
}
QT_WARNING_POP
QT_END_MOC_NAMESPACE
moc_whatismoc.cpp 文件分析
片段一
结构体qt_meta_stringdata_WhatIsMoc_t
- moc 文件的开头为结构体
struct qt_meta_stringdata_WhatIsMoc_t {
QByteArrayData data[10]; //信号函数3个、信号函数各个参数共4个、槽函数3个
char stringdata0[74];
};
结构体内含两个数组 其中
QByteArrayData
在qarraydata.h
中
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;
}
const void *data() const
{
Q_ASSERT(size == 0
|| offset < 0 || size_t(offset) >= sizeof(QArrayData));
return reinterpret_cast<const char *>(this) + offset;
}
// 以下省略
};
size是指针指向数据的大小 offset是数据指针和当前对象指针的距离(偏移量)
如果数据大小不是0,data函数就根据偏移量offset和当前对象的地址返回当前数据的指针
片段二
宏QT_MOC_LITERAL
和qt_meta_stringdata_WhatIsMoc
- 宏
QT_MOC_LITERAL
的实现
#define QT_MOC_LITERAL(idx, ofs, len) \
Q_STATIC_BYTE_ARRAY_DATA_HEADER_INITIALIZER_WITH_OFFSET(len, \
qptrdiff(offsetof(qt_meta_stringdata_WhatIsMoc_t, stringdata0) + ofs \
- idx * sizeof(QByteArrayData)) \
)
分为两部分
宏:Q_STATIC_BYTE_ARRAY_DATA_HEADER_INITIALIZER_WITH_OFFSET
参数:(len, qptrdiff(offsetof(qt_meta_stringdata_moctest_t, stringdata0) + ofs - idx * sizeof(QByteArrayData)))
部分一
宏Q_STATIC_BYTE_ARRAY_DATA_HEADER_INITIALIZER_WITH_OFFSET
展开如下
#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 } \
{}
里面的内容正好用来初始化QArrayData
中的成员变量
size
对应Q_REFCOUNT_INITIALIZE_STATIC
,值是-1
alloc
和capacityReserved
值都是0
offset
对应offset
部分二
参数(len, qptrdiff(offsetof(qt_meta_stringdata_moctest_t, stringdata0) + ofs - idx * sizeof(QByteArrayData)))
len
对应size
qptrdiff
就是一个数,数据类型为int,offsetof
用于求结构体中一个成员在该结构体中的偏移量,在stddef.h
头文件中,qptrdiff(offsetof(qt_meta_stringdata_moctest_t, stringdata0) + ofs - idx * sizeof(QByteArrayData))
对应offset
算出来这两个数据的值,然后初始化QByteArrayData
数组
- 结构体
qt_meta_stringdata_WhatIsMoc
内容
static const qt_meta_stringdata_WhatIsMoc_t qt_meta_stringdata_WhatIsMoc = {
{
QT_MOC_LITERAL(0, 0, 9), // "WhatIsMoc"
QT_MOC_LITERAL(1, 10, 8), // "sigTest1"
QT_MOC_LITERAL(2, 19, 0), // ""
QT_MOC_LITERAL(3, 20, 4), // "text"
QT_MOC_LITERAL(4, 25, 8), // "sigTest2"
QT_MOC_LITERAL(5, 34, 3), // "num"
QT_MOC_LITERAL(6, 38, 8), // "sigTest3"
QT_MOC_LITERAL(7, 47, 8), // "sltTest1"
QT_MOC_LITERAL(8, 56, 8), // "sltTest2"
QT_MOC_LITERAL(9, 65, 8) // "sltTest3"
},
"WhatIsMoc\0sigTest1\0\0text\0sigTest2\0num\0"
"sigTest3\0sltTest1\0sltTest2\0sltTest3"
};
#undef QT_MOC_LITERAL
这个结构体就是片段一中的结构体 该结构体的第一个数组就是
QByteArrayData
所以宏QT_MOC_LITERAL
返回的一定是QByteArrayData
类型数据
QT_MOC_LITERAL
宏后面的字符串对应片段一中结构体qt_meta_stringdata_WhatIsMoc_t
中的第二个数组
字符串的内容分别是类名、信号、信号参数、槽
- 总结
这一部分会通过宏
QT_MOC_LITERAL
初始化片段一中结构体qt_meta_stringdata_WhatIsMoc_t
片段三
数组qt_meta_data_WhatIsMoc[]
- 数组
qt_meta_data_WhatIsMoc[]
内容
static const uint qt_meta_data_WhatIsMoc[] = {
// content:
7, // revision
0, // classname
0, 0, // classinfo
6, 14, // methods
0, 0, // properties
0, 0, // enums/sets
0, 0, // constructors
0, // flags
3, // signalCount
// signals: name, argc, parameters, tag, flags
1, 1, 44, 2, 0x06 /* Public */,
4, 2, 47, 2, 0x06 /* Public */,
6, 1, 52, 2, 0x06 /* Public */,
// slots: name, argc, parameters, tag, flags
7, 1, 55, 2, 0x0a /* Public */,
8, 2, 58, 2, 0x0a /* Public */,
9, 1, 63, 2, 0x0a /* Public */,
// signals: parameters
QMetaType::Void, QMetaType::QString, 3,
QMetaType::Void, QMetaType::QString, QMetaType::Int, 3, 5,
QMetaType::Void, QMetaType::QString, 3,
// slots: parameters
QMetaType::Void, QMetaType::QString, 3,
QMetaType::Void, QMetaType::QString, QMetaType::Int, 3, 5,
QMetaType::Void, QMetaType::QString, 3,
0 // eod
};
- 数组分解
部分一
// content:
7, // revision
0, // classname
0, 0, // classinfo
6, 14, // methods
0, 0, // properties
0, 0, // enums/sets
0, 0, // constructors
0, // flags
3, // signalCount
revison
:版本号,不用管
classname
:类名在stringdata0
中的索引,总是0,qt_meta_data_WhatIsMoc.data[0].data()
classinfo
:不用管
methods
:信号和槽总数量6,从qt_meta_data_WhatIsMoc.data[13]
开始描述
properties
:属性数量0,数组起始位置0
signalCount
:信号数量3
这些数据存储在如下结构体QMetaObjectPrivate
中
struct QMetaObjectPrivate
{
// revision 7 is Qt 5.0 everything lower is not supported
// revision 8 is Qt 5.12: It adds the enum name to QMetaEnum
enum { OutputRevision = 8 }; // Used by moc, qmetaobjectbuilder and qdbus
int revision;
int className;
int classInfoCount, classInfoData;
int methodCount, methodData;
int propertyCount, propertyData;
int enumeratorCount, enumeratorData;
int constructorCount, constructorData;
int flags;
int signalCount;
//以下省略
};
部分二
// signals: name, argc, parameters, tag, flags
1, 1, 44, 2, 0x06 /* Public */,
4, 2, 47, 2, 0x06 /* Public */,
6, 1, 52, 2, 0x06 /* Public */,
// slots: name, argc, parameters, tag, flags
7, 1, 55, 2, 0x0a /* Public */,
8, 2, 58, 2, 0x0a /* Public */,
9, 1, 63, 2, 0x0a /* Public */,
第一列:表示信号槽的索引
第二列:表示信号槽函数的参数个数
第三列:表示参数数据的描述是从数组qt_meta_data_WhatIsMoc.data[n]
开始描述的
第四列:表示tag信息
第五列:表示信号槽函数标志位
信号槽函数标志位在qmetaobject_p.h
里声明,声明如下
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
};
将上述枚举按位或,就能得到第五列数据
以第一行数据1, 1, 44, 2, 0x06 /* Public */
为例,0x06 = 0x02 | 0x04
,表示public signal
部分三
// signals: parameters
QMetaType::Void, QMetaType::QString, 3,
QMetaType::Void, QMetaType::QString, QMetaType::Int, 3, 5,
QMetaType::Void, QMetaType::QString, 3,
// slots: parameters
QMetaType::Void, QMetaType::QString, 3,
QMetaType::Void, QMetaType::QString, QMetaType::Int, 3, 5,
QMetaType::Void, QMetaType::QString, 3,
0 // eod
以第一行数据
QMetaType::Void, QMetaType::QString, 3,
为例
QMetaType::Void
:返回参数
QMetaType::QString
:形参
片段四
结构体WhatIsMoc::staticMetaObject
- 结构体内容
const QMetaObject WhatIsMoc::staticMetaObject = {
{ &QObject::staticMetaObject,
qt_meta_stringdata_WhatIsMoc.data,
qt_meta_data_WhatIsMoc,
qt_static_metacall,
nullptr,
nullptr}
};
WhatIsMoc::staticMetaObject
的类型是QMetaObject
QMetaObject
的结构在qobjectdefs.h
中声明
struct Q_CORE_EXPORT QMetaObject
{
struct { // private data
SuperData superdata;
const QByteArrayData *stringdata;
const uint *data;
typedef void (*StaticMetacallFunction)(QObject *, QMetaObject::Call, int, void **);
StaticMetacallFunction static_metacall;
const SuperData *relatedMetaObjects;
void *extradata; //reserved for future use
} d;
};
superdata
:初始值为QMetaObject::SuperData::link<QObject::staticMetaObject>()
,表示基类的元对象数据
stringdata
:初始值为qt_meta_stringdata_WhatIsMoc.data
,指向的是qt_meta_stringdata_WhatIsMoc_t
中的data
数组
data
:初始值为qt_meta_data_WhatIsMoc
,该指针指向数组qt_meta_data_WhatIsMoc
typedef void (*StaticMetacallFunction)(QObject *, QMetaObject::Call, int, void **);
声明了一个函数指针,指针的类型是void (*)(QObject *, QMetaObject::Call, int, void **);
static_metacall
:初始值为qt_static_metacall
relatedMetaObjects
:相关元对象指针
extradata
:额外数据
片段五
公有接口metaObject
、qt_metacall
、qt_metacast
- 公有接口的定义
//获取元对象,可以调用this->metaObject()->className();获取类名称
const QMetaObject *WhatIsMoc::metaObject() const
{
return QObject::d_ptr->metaObject ? QObject::d_ptr->dynamicMetaObject() : &staticMetaObject;
}
//这个函数负责将传递来到的类字符串描述转化为void*
void *WhatIsMoc::qt_metacast(const char *_clname)
{
if (!_clname) return nullptr;
if (!strcmp(_clname, qt_meta_stringdata_WhatIsMoc.stringdata0))
return static_cast<void*>(this);
return QObject::qt_metacast(_clname);
}
//调用方法
int WhatIsMoc::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 < 6)
qt_static_metacall(this, _c, _id, _a);
_id -= 6;
} else if (_c == QMetaObject::RegisterMethodArgumentMetaType) {
if (_id < 6)
*reinterpret_cast<int*>(_a[0]) = -1;
_id -= 6;
}
return _id;
}
这些接口是可以在自己代码里直接调用
信号槽调用实现qt_static_metacall
- 接口定义
void WhatIsMoc::qt_static_metacall(QObject *_o, QMetaObject::Call _c, int _id, void **_a)
{
if (_c == QMetaObject::InvokeMetaMethod) {
WhatIsMoc *_t = static_cast<WhatIsMoc *>(_o);
Q_UNUSED(_t)
switch (_id) {
case 0: _t->sigTest1((*reinterpret_cast< const QString(*)>(_a[1]))); break;
case 1: _t->sigTest2((*reinterpret_cast< const QString(*)>(_a[1])),(*reinterpret_cast< int(*)>(_a[2]))); break;
case 2: _t->sigTest3((*reinterpret_cast< const QString(*)>(_a[1]))); break;
case 3: _t->sltTest1((*reinterpret_cast< const QString(*)>(_a[1]))); break;
case 4: _t->sltTest2((*reinterpret_cast< const QString(*)>(_a[1])),(*reinterpret_cast< int(*)>(_a[2]))); break;
case 5: _t->sltTest3((*reinterpret_cast< const QString(*)>(_a[1]))); break;
default: ;
}
} else if (_c == QMetaObject::IndexOfMethod) {
int *result = reinterpret_cast<int *>(_a[0]);
{
typedef void (WhatIsMoc::*_t)(const QString & );
if (*reinterpret_cast<_t *>(_a[1]) == static_cast<_t>(&WhatIsMoc::sigTest1)) {
*result = 0;
return;
}
}
{
typedef void (WhatIsMoc::*_t)(const QString & , int );
if (*reinterpret_cast<_t *>(_a[1]) == static_cast<_t>(&WhatIsMoc::sigTest2)) {
*result = 1;
return;
}
}
{
typedef void (WhatIsMoc::*_t)(const QString & );
if (*reinterpret_cast<_t *>(_a[1]) == static_cast<_t>(&WhatIsMoc::sigTest3)) {
*result = 2;
return;
}
}
}
}
执行对象所对应的信号或槽
对信号槽函数进行参数检查
信号定义
// SIGNAL 0
void WhatIsMoc::sigTest1(const QString & _t1)
{
void *_a[] = { nullptr, const_cast<void*>(reinterpret_cast<const void*>(&_t1)) };
QMetaObject::activate(this, &staticMetaObject, 0, _a);
}
// SIGNAL 1
void WhatIsMoc::sigTest2(const QString & _t1, int _t2)
{
void *_a[] = { nullptr, const_cast<void*>(reinterpret_cast<const void*>(&_t1)), const_cast<void*>(reinterpret_cast<const void*>(&_t2)) };
QMetaObject::activate(this, &staticMetaObject, 1, _a);
}
// SIGNAL 2
void WhatIsMoc::sigTest3(const QString & _t1)
{
void *_a[] = { nullptr, const_cast<void*>(reinterpret_cast<const void*>(&_t1)) };
QMetaObject::activate(this, &staticMetaObject, 2, _a);
}
信号之所以不用定义,是因为其定义有Qt框架完成,并与类的源文件一同编译
信号函数实现:
- 定义一个void*的指针数组,数组的第一个元素都是空,给元对系统内部注册元方法参数类型时使用,剩下的元素都是信号函数的参数的指针,然后将数组传入activate
总结
- 宏
Q_OBJECT
是Qt框架建立元对象系统的关键部分 - moc文件是关于宏
Q_OBJECT
中函数声明的定义以及结构体的赋值 - 信号-槽机制就是建立“注册索引”的机制
注意
- 文章内容以信号-槽
connect
函数第五个参数是默认为前提