说Qt信号与槽是一个很好机制,不如说Qt的元对象系统很强大。这也是大家讲Qt就必须将信号与槽,讲信号与槽就要讲Qt的元对象系统。当然初学者知道怎么用就OK啦,当然随着你写的代码越多,接触的平台越多的时候,你就会好奇Qt是如何把两个(多个)任意不相关(必须都继承与QObject)的对象联系在一起的。我们围绕一些问题来认识一下Qt元对象系统:

  • 什么是Qt元对象系统,它包含了哪些内容,它在我们的程序中做了什么?

  • moc工具是什么,Q_OBJECT宏是什么?

  • 元对象系统如何工作在Qml、C++、Javvascrip的混合编程的?

  • 信号与槽机制、Qt事件机制、MFC消息机制三者的区别是什么?

  • 信号与槽在单线程与多线程中是如何工作的?

  • 如何在信号与槽机制中,传递自定义类型参数? 
    什么是Qt元对象系统 
    元对象系统是一个基于标准C++的扩展,为Qt提供了1、信号与槽机制2、实时类型信息3、动态属性系统。 
    这个元对象主要基于三个东西:

  • Object类。大家都知道QObject类是Qt的核心类,很多Qt类都是由它继承而来,那它具体到底是什么东西呢?我们一起去看下Object的Detail Description我们一起来趴一下它的主要特性: 
    (1)它是对象模型的核心,信号与槽是基于对象模型的(两个对象的连接),而它是对象模型的核心。体现在我们常用的QObject::connect()函数上,我们后面会分析这个conncet()源码,趴一下它是怎么工作的。 
    (2)对象的组织方式以树形结构的。这也就是Qt框架那章Core模块的一个特性“树形对象模型”。我们常用相关的函数体现在QObject::setParent()、QObject::findChild()、QObject::findChilren()这几个函数上。这种树形结构保持了众多对象之间的严密的父子、逻辑关系。 
    (3)每一个对象都有一个独立的名字,并且可以查出该对象的继承关系。这些对象不同的名字是我们使用findChild()函数的关键,也是我们在Qml、C++混合编程时的关键。这里QObject有这个属性,并不是它自己实现的,是QMetaobject帮助实现的,QMetaObject是设置这些属性规则,并建立对象们之间的关系的关键。(每个人都有自己名字手机QQ,但是你们怎么相互联系呢,它就是帮助建立通讯录) 
    (4)对象在销毁时会发出一个信号。这里没什么好多说的。 
    (5)添加安装事件过滤器。让对象接受或者不接受某些事件以及事件的处理。我们常用到的有mouseEvent()、timeEvent(),在某些没有继承Object类中是不能使用这些函数的,如QGraphicsItem以及它派生出来的其他图元类。后面我们会讲事件与信号槽的区别。 
    前面(1)(2)(3)是Object与元对象系统紧密联系的属性,其他属性大家可以去看看帮助文档扒一扒,小白英文太烂。到这里你只要明白为什么元对象非要和QObject相关就行啦。

  • Q_OBJECT。简单理解就是一些宏定义代码,就是你们自己定义的一些类、类的信号、槽函数、(Qml混合编程的属性、自己注册的Qt数据类型等)这么多属性,怎么保存到通讯录里面呢?就是通过这个宏定义的函数,帮助你们实现的,后面会结合moc文件讲解这个函数是做什么的。

  • moc(Meta-Object-Compiler)元对象编译器,从概念上和其他编译器一样来理解就好了。signals、slots关键字并不是标准C++里面的东西,代码最后要交给C++编译器,那么就需要把这部分转化成C++编译器认识的东西,这个工作就是moc来完成了。这里需要注意的是,moc过程是发生在预编译之前的,简单说就是moc之后每一个包含Q_OBJECT宏头文件,都会根据该头文件里面的signals、slots、Q_MENU l来生成以moc_XXXX(自定义类名)的.cpp文件,我们常用IDE的构建生成的.o文件,就是最终的目标文件(包含moc生成的cpp)。这个中间生成用qamke生成Makefile可以清楚的看到编译文件的连接情况。后面讲Qt工程的时候会讲解Makefile。这里大家想要理解moc更多的使用规则,帮助里面输入moc查看帮助文档,这里推荐也个中文翻译版(小白英语实在太烂)http://www.kuqin.com/qtdocument/moc.html 
    其实大家都知道这三个基本原则,小白在这里也碰到一个疑问,在《零基础学Qt4编程》里面说moc在生成cpp文件的同时,也会生成头文件XXXX.moc.h格式,很显然小白是没有这个文件的,在帮助里看到的也是read a C++ source file。C++编译器在预编译处理过程中就是处理头文件,如果Qt没有转换头文件,C++编译器怎么认识signals、slots