我刚开始使用Qt,注意到所有示例类的定义都有宏
Q_OBJECT
作为第一行。这个预处理器宏的目的是什么?来自Qt文档:
元对象编译器(moc)是处理Qt的C++扩展的程序。
moc工具读取C++头文件。如果它发现一个或多个包含Q_OBJECT宏的类声明,它将生成一个C++源文件,其中包含这些类的元对象代码。除其他外,元对象代码需要用于信号和槽机制、运行时类型信息和动态属性系统。
这段代码告诉预编译器,该类需要通过'moc'或Meta-Object Compiler运行,moc会为该类添加额外的隐藏字段和函数,并解析信号和槽。只有使用信号/槽机制或其他Qt类级功能(例如内省)的类才需要添加此代码。对于仅使用标准C++功能的类,无需添加Q_OBJECT。
Q_OBJECT
是错误的。缺少 Q_OBJECT
会破坏 qobject_cast
和反射(introspection)功能,这可能导致一些混乱的行为,因此这是一个不好的想法。 - Kuba hasn't forgotten MonicaQObject
类中,“Q_OBJECT”不会被“悄悄地”忽略,这是不正确的说法。根据C++标准,它通过声明一些永远不会被定义的成员函数和变量引入了未定义的行为。它还将您的类命名空间污染为QObject
特定成员。例如,一个Q_OBJECT
可能会破坏一个包含名为“metaObject”的方法的无关类。 - Kuba hasn't forgotten MonicaQ_OBJECT
宏,但是拥有宏的非GUI类以及没有宏的GUI类也是完全有意义的。该宏很有用,但不仅限于GUI类,也不是必需的。 - pasbiMOC (元对象编译器)将包含 Q_OBJECT 宏的头文件转换为C++等效源代码。它主要控制信号槽机制,并使其对C++编译器可读。
Q_OBJECT
宏是由编译器展开的,不需要 moc。moc 不会对宏本身进行任何操作,但它会生成 Q_OBJECT
宏所声明的成员变量和方法的定义。 - Kuba hasn't forgotten Monica1 来自Qt文档的元对象系统
moc工具读取C++源文件。如果它发现一个或多个类声明包含Q_OBJECT宏,它将为每个类生成元对象代码的另一个C++源文件。此生成的源文件要么被#include到类的源文件中,要么更常见的是与类的实现一起编译和链接。
2 来自Qt文档的Q_OBJECT
Q_OBJECT宏必须出现在类定义的私有部分中,该类声明其自己的信号和槽,或使用Qt元对象系统提供的其他服务。
3 来自Qt文档的moc
The moc工具读取C++头文件。如果它找到一个或多个包含Q_OBJECT宏的类声明,它将生成一个包含这些类的元对象代码的C++源文件。元对象代码除了其他功能外,还需要用于信号和槽机制、运行时类型信息和动态属性系统。在gcc中,使用-E
可以查看扩展的宏。这是在Linux上gcc中Q_OBJECT
扩展成的内容。请注意,这可能与平台相关,并且可能会根据QT版本而更改。您可以看到它不仅仅是moc编译器的标签。
# 11 "mainwindow.hh"
#pragma GCC diagnostic push
# 11 "mainwindow.hh"
# 11 "mainwindow.hh"
#pragma GCC diagnostic ignored "-Wsuggest-override"
# 11 "mainwindow.hh"
static const QMetaObject staticMetaObject; virtual const QMetaObject *metaObject() const; virtual void *qt_metacast(const char *); virtual int qt_metacall(QMetaObject::Call, int, void **); static inline QString tr(const char *s, cons
t char *c = nullptr, int n = -1) { return staticMetaObject.tr(s, c, n); } __attribute__ ((__deprecated__)) static inline QString trUtf8(const char *s, const char *c = nullptr, int n = -1) { return staticMetaObject.tr(s, c, n); } private:
# 11 "mainwindow.hh"
#pragma GCC diagnostic ignored "-Wattributes"
# 11 "mainwindow.hh"
__attribute__((visibility("hidden"))) static void qt_static_metacall(QObject *, QMetaObject::Call, int, void **);
# 11 "mainwindow.hh"
#pragma GCC diagnostic pop
# 11 "mainwindow.hh"
struct QPrivateSignal {};
Q_OBJECT宏必须出现在类定义的私有部分中,该类定义声明其自己的信号和槽或使用Qt元对象系统提供的其他服务。
QObject
的类都必须出现Q_OBJECT
宏。当该宏缺失时,您的代码将会出现微妙的错误,仅仅因为它编译通过并不代表它是正确的。 - Kuba hasn't forgotten MonicaQ_OBJECT
宏的情况下,它可以编译但不起作用? - ChrisQ_OBJECT
的实现,你会发现它使用了访问说明符。因此,无论这个宏出现在private
、protected
还是public
说明符下都是无关紧要的——把它放在类的开头只是一种惯例。 - TrebledJ
Q_OBJECT::connect()
,而只需要编写connect()
? - mLstudent33