类中漏掉Q_OBJECT宏会导致connect函数不能使用。
如果没有Q_OBJECT,则不会生成多余的cpp文件
加上Q_OBJECT即使不用connect等相关函数都会生成moc_xxx.cpp文件
其中,cpp文件里面定义了结构体和几个函数,.h文件里面定义了很多宏。
只有继承了QObject类的类,才具有信号槽的能力。所以,为了使用信号槽,必须继承QObject。凡是QObject类(不管是直接子类还是间接子类),都应该在第一行代码写上Q_OBJECT。不管是不是使用信号槽,都应该添加这个宏。这个宏的展开将为我们的类提供信号槽机制、国际化机制以及 Qt 提供的不基于 C++ RTTI 的反射能力。因此,如果你觉得你的类不需要使用信号槽,就不添加这个宏,就是错误的。其它很多操作都会依赖于这个宏。
由于 moc 只处理头文件中的标记了Q_OBJECT的类声明,不会处理 cpp 文件中的类似声明。因此,如果我们的类位于 main.cpp 中,是无法得到 moc 的处理的。解决方法是,我们手动调用 moc 工具处理 main.cpp,并且将 main.cpp 中的#include “xxx.h”改为#include “moc_xxx.h”就可以了。不过,这是相当繁琐的步骤,为了避免这样修改,我们还是将其放在头文件中。许多初学者会遇到莫名其妙的错误,一加上Q_OBJECT就出错,很大一部分是因为没有注意到这个宏应该放在头文件中。
MOC
QT的元对象编译器MOC(Meta-Object Compiler)是一个预处理器,在源程序被编译前先将这些QT特性的程序转为标准的C++兼容的形式**,然后再被标准的C++编译器进行编译。也就是为什么在使用信号和槽的机制的类里,必须添加一个Q_OBJECT宏的原因,只有添加了这个宏,moc才能对类里的信号与槽代码进行预处理。
构建项目时MOC工具读取C++源文件,当它发现类的定义里有Q_OBJECT宏时,它会为这个类生成另外一个包含有元对象支持代码的C++源文件,也就是moc_xxx.cpp文件,这个生成的源文件连同类的实现文件一起被编译和连接。
Q_OBJECT是Qt实现元编译系统的一个关键宏,这个宏展开后,里边包含了很多Qt帮助我们写的代码,包括了变量定义、函数声明等等,
Qt 使用 moc,为标准 C++ 增加了一些特性:
信号槽机制,用于解决对象之间的通讯,这个我们已经了解过了,可以认为是 Qt 最明显的特性之一;
可查询,并且可设计的对象属性;
强大的事件机制以及事件过滤器;
基于上下文的字符串翻译机制(国际化),也就是 tr() 函数,我们简单地介绍过;
复杂的定时器实现,用于在事件驱动的 GUI 中嵌入能够精确控制的任务集成;
层次化的可查询的对象树,提供一种自然的方式管理对象关系。
智能指针(QPointer),在对象析构之后自动设为 0,防止野指针;
能够跨越库边界的动态转换机制。
通过继承QObject类,我们可以很方便地获得这些特性。当然,这些特性都是由 moc 帮助我们实现的。moc 其实实现的是一个叫做元对象系统(meta-object system)的机制。正如上面所说,这是一个标准 C++ 的扩展,使得标准 C++ 更适合于进行 GUI 编程。虽然利用模板可以达到类似的效果,但是 Qt 没有选择使用模板。按照 Qt 官方的说法,模板虽然是内置语言特性,但是其语法实在是复杂,并且由于 GUI 是动态的,利用静态的模板机制有时候很难处理。而自己使用 moc 生成代码更为灵活,虽然效率有些降低(一个信号槽的调用大约相当于四个模板函数调用),不过在现代计算机上,这点性能损耗实在是可以忽略。
参考
https://blog.csdn.net/u011555996/article/details/124438676
https://zhuanlan.zhihu.com/p/620384700
https://www.devbean.net/2012/09/qt-study-road-2-objects-model/
https://blog.csdn.net/u012564117/article/details/102631264