前言
之前一直停留在使用Qt库的层面,底层的实现也只是了解到一些皮毛而已,现在需要更深的了解它的实现原理,对以后开发会有很大的帮助。
概述
按照我整个深入了解的过程,介绍以下几点主要内容:
- signals和slots宏
- MOC 元对象编译器
- connect连接实现
- emit发送实现
signals和slots宏
Qt中的signals和slots两个宏的源码:
# define slots Q_SLOTS
# define signals Q_SIGNALS
# define Q_SLOTS QT_ANNOTATE_ACCESS_SPECIFIER(qt_slot)
# define Q_SIGNALS public QT_ANNOTATE_ACCESS_SPECIFIER(qt_signal)
可以看到的是这两个宏是没有意义的,那编译的时候怎么去处理呢?如何辨别哪个是信号,哪个是槽函数呢?
带着这些问题查找资料… …
MOC 元对象编译器
标准C++不支持Qt的元对象系统,所以Qt单独提供了MOC工具来解决和C++的兼容问题。
MOC在预处理的时候,读取C++头文件,如果包含Q_OBJECT宏,则将生成一个C++源文件(moc_headername.cpp)。然后将新生成的源文件和其他文件一起进行编译、链接生成程序。
下面列举我创建的简单的Qt项目来看一下moc生成的源文件:
.h:
class QWidgetTest : public QWidget
{
Q_OBJECT
public:
QWidgetTest(QWidget *parent = Q_NULLPTR);
private:
Ui::QWidgetTestClass ui;
private:
int a_;
public:
void func(int a);
signals:
void sigTest();
void sigTttt(int a);
public slots:
void onTest();
void onButtonClicked();
};
.cpp:
QWidgetTest::QWidgetTest(QWidget *parent)
: QWidget(parent)
{
ui.setupUi(this);
connect(this, SIGNAL(sigTest()), this, SLOT(onTest()));
connect(ui.pushButton, SIGNAL(clicked()), this, SLOT(onButtonClicked()));
}
void QWidgetTest::func(int a)
{
}
void QWidgetTest::onTest()
{
}
void QWidgetTest::onButtonClicked()
{
emit sigTest();
}
下面将一部分一部分来介绍MOC预处理生成的moc_QWidgetTest.cpp文件。
// 该结构是存储类中的信号、信号参数、槽函数以及类名
struct qt_meta_stringdata_QWidgetTest_t {
QByteArrayData data[7]; // 有7个信息
char stringdata0[54]; // 将这些信息按照顺序组成字符串存储
};
/*
idx: 信息对应的索引值
ofs: 在字符串中的偏移量
len: 偏移长度
*/
#define QT_MOC_LITERAL(idx, ofs, len) \
Q_STATIC_BYTE_ARRAY_DATA_HEADER_INITIALIZER_WITH_OFFSET(len, \
qptrdiff(offsetof(qt_meta_stringdata_QWidgetTest_t, stringdata0) + ofs \
- idx * sizeof(QByteArrayData)) \
)
static const qt_meta_stringdata_QWidgetTest_t qt_meta_stringdata_QWidgetTest = {
{
QT_MOC_LITERAL(0, 0</