Qt 中 Q_OBJECT 宏及 moc_*.cpp文件
Qt 中 Q_OBJECT 宏及 moc_前缀文件
- Q_OBJECT 宏
- 元对象系统 (Meta-Object System)
- 了解 Q_OBJECT 宏
- 展开 Q_OBJECT 宏
- MOC 预编译器
- MOC (Meta-Object Compiler)
- 前缀 moc_xx.cpp文件
- 代码示例如下
- MakeFile文件
- 生成的moc文件如下
- ==moc_whatismoc.cpp== 文件分析
- 片段一
- 结构体`qt_meta_stringdata_WhatIsMoc_t`
- 片段二
- 宏`QT_MOC_LITERAL`和`qt_meta_stringdata_WhatIsMoc`
- 片段三
- 数组`qt_meta_data_WhatIsMoc[]`
- 片段四
- 结构体`WhatIsMoc::staticMetaObject`
- 片段五
- 公有接口`metaObject`、`qt_metacall`、`qt_metacast`
- 信号槽调用实现`qt_static_metacall`
- 信号定义
- 总结
- 注意
- 文章参考
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.)"
#endifQT_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_LITERALstatic const uint qt_meta_data_WhatIsMoc[] = {// content:7, // revision0, // classname0, 0, // classinfo6, 14, // methods0, 0, // properties0, 0, // enums/sets0, 0, // constructors0, // flags3, // signalCount// signals: name, argc, parameters, tag, flags1, 1, 44, 2, 0x06 /* Public */,4, 2, 47, 2, 0x06 /* Public */,6, 1, 52, 2, 0x06 /* Public */,// slots: name, argc, parameters, tag, flags7, 1, 55, 2, 0x0a /* Public */,8, 2, 58, 2, 0x0a /* Public */,9, 1, 63, 2, 0x0a /* Public */,// signals: parametersQMetaType::Void, QMetaType::QString, 3,QMetaType::Void, QMetaType::QString, QMetaType::Int, 3, 5,QMetaType::Void, QMetaType::QString, 3,// slots: parametersQMetaType::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 headervoid *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, // revision0, // classname0, 0, // classinfo6, 14, // methods0, 0, // properties0, 0, // enums/sets0, 0, // constructors0, // flags3, // signalCount// signals: name, argc, parameters, tag, flags1, 1, 44, 2, 0x06 /* Public */,4, 2, 47, 2, 0x06 /* Public */,6, 1, 52, 2, 0x06 /* Public */,// slots: name, argc, parameters, tag, flags7, 1, 55, 2, 0x0a /* Public */,8, 2, 58, 2, 0x0a /* Public */,9, 1, 63, 2, 0x0a /* Public */,// signals: parametersQMetaType::Void, QMetaType::QString, 3,QMetaType::Void, QMetaType::QString, QMetaType::Int, 3, 5,QMetaType::Void, QMetaType::QString, 3,// slots: parametersQMetaType::Void, QMetaType::QString, 3,QMetaType::Void, QMetaType::QString, QMetaType::Int, 3, 5,QMetaType::Void, QMetaType::QString, 3,0 // eod
};
- 数组分解
部分一
// content:7, // revision0, // classname0, 0, // classinfo6, 14, // methods0, 0, // properties0, 0, // enums/sets0, 0, // constructors0, // flags3, // 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 QMetaEnumenum { OutputRevision = 8 }; // Used by moc, qmetaobjectbuilder and qdbusint 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, flags1, 1, 44, 2, 0x06 /* Public */,4, 2, 47, 2, 0x06 /* Public */,6, 1, 52, 2, 0x06 /* Public */,// slots: name, argc, parameters, tag, flags7, 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, //maskMethodMethod = 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: parametersQMetaType::Void, QMetaType::QString, 3,QMetaType::Void, QMetaType::QString, QMetaType::Int, 3, 5,QMetaType::Void, QMetaType::QString, 3,// slots: parametersQMetaType::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 dataSuperData 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
函数第五个参数是默认为前提
文章参考
深入分析Qt信号与槽(下)
MOC文件解读(上)——MOC文件中的数据
MOC文件解读(下)——MOC文件中的函数
Qt 中 Q_OBJECT 宏及 moc_*.cpp文件相关推荐
- Qt中Q_OBJECT与生成的moc文件的作用
一.先来了解Q_OBJECT 只有继承了QObject类的类,才具有信号槽的能力.所以,为了使用信号槽,必须继承QObject.凡是QObject类(不管是直接子类还是间接子类),都应该在第一行代码写 ...
- qmoc文件_Qt中Q_OBJECT与生成的moc文件的作用
Qt中Q_OBJECT与生成的moc文件的作用 一.先来了解Q_OBJECT 只有继承了QObject类的类,才具有信号槽的能力.所以,为了使用信号槽,必须继承QObject.凡是QObject类(不 ...
- qt中生成含有中文的json文件,读取含有中文的json文件
引言 之前将变量保存并在本地生成json文件,由于其中含有中文,导致生成的json文件出现乱码,或者就是生成的json文件没有乱码,但是读取生成的json文件时出现乱码,不能正常解析json. 示例 ...
- 解决qt中cmake单独存放 .ui, .cpp, .h文件
创建时间:2023-02-18 17:58:04 设想 项目文件较多,全部放在一个目录下就像依托答辩. 希望能将头文件放入include,ui文件放入ui,源文件放入src. 为了将Qt代码和一般非Q ...
- 2.关于QT中的Dialog(模态窗口),文件选择器,颜色选择器,字体选择器,消息提示窗口
1 新建一个空项目 A 编写 .pro文件 QT += gui widgets HEADERS += \ MyDialog.h SOURCES += \ MyDialog.cpp B 编写MyD ...
- Qt中Q_D宏及d指针
原文标题:d指针在Qt上的应用及实现 原文链接:http://blog.csdn.net/rabinsong/article/details/9474859 正文: Qt为了使其动态库最大程度上实现二 ...
- BlackBerry 10:Qt中使用OpenAL播放wav声音文件
BlackBerry 10/PlayBook OS 2.0里面都内置OpenAL的类库,所以在程序中使用OpenAL类库播放声音是很方便的. BlackBerry 10开发者网站上提供的例子程序Cow ...
- qt中生成含有中文的json文件和解析json文件
提要 生成的json文件在程序加载解析时出现上述错误,究其原因是生成json文件过程中编码问题.qt编译器默认的编码格式为utf-8,而windows一般为gbk编码,所以就需要在生成本地json文件 ...
- Qt笔记-Qt中Json存二进制文件并读取文件(QJsonObject、QJsonArray、QJsonDocument的使用)
程序运行截图如下: 文件如下: 源码如下: #include <QCoreApplication> #include <QJsonDocument> #include < ...
- QT中pro、pri、prf、prl文件
QT .pro文件 在QT中使用qmake自动生成pro文件,如果要自己定制工程选项,则需要自行修改pro文件. pro文件有以下关键字:TEMPLATE.TARGET.DESTDIR.DEPENDP ...
最新文章
- 关于ARP、MAC、IP欺骗以及TCP劫持
- java如何使显示字符下标_Java如何在 Word 中设置上、下标
- linux 的git的安装目录,Linux下Git安装及配置较详细-Go语言中文社区
- oracle 查找上一个,查看ORACLE_HOME的另外一个方法
- Linux安装redis和部署
- 贺利坚老师汇编课程37笔记:运用栈加两层循环之把六个字符串里的字母都改写成大写字母
- Eclipse启动报错:A java runtime Environment(JRE) or java Development……的解决办法
- 算法 第四版 2.1.25 不需要交换的插入排序
- 如何实现某个软件的单独断网/稳定地解决fluent断网计算中止问题/tecplot联网后打开程序出现报错问题
- 软件构造笔记---Java的多态性
- WIN7系统的虚拟机C盘扩容步骤
- 深度至尊 GHOST XP SP3 纯净版 V4.0
- java.lang.Byte常用方法
- GSR引擎专用工具更新使用贴子
- CCF201509-1数列分段(C语言)
- 挂载zookeeper到文件系统 (mount zookeeper)
- css 从右到左滚动,CSS 文字从左到右滚动 (右进左出)
- MTK 按键驱动流程总结
- 2016年8月23日 星期二 --出埃及记 Exodus 16:24
- 修复恢复可疑的SQLServer数据库