Qt信号槽原理

1、说明

使用Qt已经好几年了,一直以为自己懂Qt,熟悉Qt,使用起来很是熟练,无论什么项目,都喜欢用Qt编写。但真正去看Qt的源码,去理解Qt的思想也就近两年的事。

本次就着重介绍一下Qt的核心功能–信号槽机制,相信接触过Qt的人都能很熟悉地使用,甚至,大部分人还能轻松地说出信息槽的几种用法。但是信号槽的核心可不是简单说说就能说清楚的。

那么,本次,就从Qt的源码中讲解一下信号槽的机制。

其实,直到写这篇文章,我也没有完全看明白相关的源码,只是明白了其中的大部分以及使用机制,其中还有很多细节的,留待以后整理。

如果错误还请大家指正。

2、环境以及知识点

Qt版本:Qt 5.5.1
系统:windows 10

在阅读本文前,希望你能:

  1. 熟练使用C++,了解make的编译方法和过程;
  2. 熟练使用Qt的信号槽功能,对信号槽的写法以及4和5的区别了如指掌;
  3. QMetaObject元数据系统;
  4. 懂一些设计模式,能理解观察者模式;

3、信号槽源码分析

以下将按照SIGNAL/SLOT宏定义连接信号槽的方式做讲解
接下来将会从按照以下的步骤来进行分析:

  1. Qt元数据系统;
  2. moc预编译;
  3. Q_OBJECT宏;
  4. signals和slots关键字以及emit;
  5. SIGNAL()和SLOT()宏;
  6. connect 方法;
  7. 触发信号;

3.1、Qt的元数据系统

没看过Qt源码的同学可能会对QMetaObject有些陌生,我们打开Qt手册,查看此类的说明,介绍如下:

The QMetaObject class contains meta-information about Qt objects.
The Qt Meta-Object System in Qt is responsible for the signals and slots inter-object communication mechanism, runtime type information, and the Qt property system. A single QMetaObject instance is created for each QObject subclass that is used in an application, and this instance stores all the meta-information for the QObject subclass. This object is available as QObject::metaObject().

这里是说,QMetaObject包含了Qt的元对象信息。元对象机制类似Java的反射机制。通过继承QObject,并在定义类是添加一定Qt内置宏,能在运行时动态获取Qt的信号槽、类型信息以及相关属性。

一个简答的例子

void MainWindow::onClickButton()
{
    qDebug()<<"on click button";
    const QMetaObject* metaObject = this->metaObject();
    qDebug()<<metaObject->className();
    qDebug()<<metaObject->superClass()->className();

    int methodIndex = metaObject->indexOfMethod("testFunction()");
    qDebug()<<methodIndex;
    qDebug()<<metaObject->method(methodIndex).name();
    metaObject->method(methodIndex).invoke(this);

    QMetaObject::invokeMethod(this, "testFunction");
}

如上,一个简单的例子,通过QMetaObject,我们得到了该对象的类名、父类名、方法并调用了该方法

怎么样,熟悉Java的小伙伴已经发现了,这不就是Java的反射吗,谁说C++没有反射呢

那么,Qt是如何实现”反射“的呢?答案是使用moc预编译

3.2、moc编译

moc全称Meta-Object Compiler,即元对象编译器。我们可以在Qt的安装目录的bin文件下看到moc工具,moc.exe。Qt的构建的时候,会调用该工具生成moc文件,我们在编译目录下看到的moc_xxx.cpp文件就是该工具生成的。

Qt的MinGW版本使用的是qmake进行项目管理,它和cmake功能类似,但没有后者强大。使用qmake生成Makefile后,我们打开Makefile文件,我们可以狠清楚地看到有一个调用moc.exe工具的地方,代码太多,就不列出来了。

此外,我们还发现,并不是所有的代码都会生成moc_xxx.cpp文件的,只有使用了 Q_OBJECT 宏的类文件,才会生成。没有错,moc工具就是根据 Q_OBJECT 宏来生成moc_xxx.cpp文件的,而实现“反射”的元数据系统的也是依靠Q_OBJECT的。

到此,我们其实已经能够大概理清qmake项目的构建步骤了。步骤和常用的cmake项目类似,区别就是,qmake生成的Makefile文件种,会写有调用moc工具的指令,以达到moc_xxx.cpp文件的生成。

我们可以使用moc工具手动生成moc_xxx.cpp,使用指令 moc.exe mainwindow.h,即会在控制台打印moc文件信息,也可以使用 -o 参数来将生成的内容写入文件,其余参数可以使用 moc.exe -h 来查看

3.3、Q_OBJECT

我们可以从源代码中查看 Q_OBJECT 的内容,这里调整一个格式,使用 Q_OBJECT 宏之后,会在类定义的开头多出以下代码:

public:
    Q_OBJECT_CHECK
    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_WARNING_POP
    QT_TR_FUNCTIONS
private:
    Q_DECL_HIDDEN_STATIC_METACALL static void qt_static_metacall(QObject *, QMetaObject::Call, int, void **);
    struct QPrivateSignal {};

可以看到,这里多出几个方法和一些变量

  1. 属性staticMetaObject,元数据对象,可以从中获取当前类的元数据
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值