【发布时间】:2010-11-25 00:16:26
【问题描述】:
我刚开始使用 Qt,注意到所有示例类定义的第一行都有宏 Q_OBJECT。这个预处理器宏的用途是什么?
【问题讨论】:
-
QT 指的是 QuickTime,Qt 指的是名为 Qt 的 C++ 库。
我刚开始使用 Qt,注意到所有示例类定义的第一行都有宏 Q_OBJECT。这个预处理器宏的用途是什么?
【问题讨论】:
元对象编译器 moc 是 处理 Qt 的 C++ 的程序 扩展。
moc 工具读取 C++ 头文件。 如果它找到一个或多个类 包含 Q_OBJECT 的声明 宏,它产生一个 C++ 源文件 包含元对象代码 那些课。除其他事项外, 元对象代码是必需的 信号和槽机制, 运行时类型信息,以及 动态属性系统。
【讨论】:
Q_OBJECT::connect() 而只是connect()?
它只是告诉预编译器这个类需要通过'moc'或元对象编译器运行,它为类添加额外的隐藏字段和函数以及解析信号和槽。您只需要将它添加到使用信号/槽机制或其他 Qt 类级别功能(例如自省)的类中。您不需要将 Q_OBJECT 添加到仅使用标准 C++ 功能的类。
【讨论】:
Q_OBJECT 的缺席打破了qobject_cast 和自省。它可能会导致一些令人困惑的行为,所以这是一个坏主意。
Q_OBJECT 不会在任何其他(非QObject)类中被“悄悄地”忽略。根据 C++ 标准,它通过声明几个从未定义的成员函数和变量来引入未定义的行为。它还会用QObject 特定的成员污染你的类的命名空间。例如。 Q_OBJECT 很可能会破坏恰好包含名为 metaObject 的方法的无关类。
Q_OBJECT 宏,但将非 gui 类与宏以及没有宏的 gui 类一起使用是非常有意义的。该宏很有用,但不仅限于 gui 类,也不是必需的。
MOC(元对象编译器)将 Q_OBJECT 宏包含的头文件转换为 C++ 等效源代码。 它基本上控制了信号槽机制,并使 C++ 编译器可以理解
【讨论】:
Q_OBJECT 宏由编译器扩展,不需要 moc。 moc 不对宏本身做任何事情,但它生成Q_OBJECT 宏已声明的成员变量和方法的定义。
moc 工具读取 C++ 源文件。如果它找到一个或多个包含 Q_OBJECT 宏的类声明,它会生成另一个 C++ 源文件,其中包含每个类的元对象代码。这个生成的源文件或者被#include 到类的源文件中,或者更常见的是,编译并与类的实现链接。
2 来自 THE Q_OBJECT
的 Qt 文档Q_OBJECT 宏必须出现在声明自己的信号和槽或使用 Qt 元对象系统提供的其他服务的类定义的私有部分中。
3 来自 moc
的 Qt 文档moc 工具读取 C++ 头文件。如果它找到一个或多个包含 Q_OBJECT 宏的类声明,它会生成一个 C++ 源文件,其中包含这些类的元对象代码。除此之外,信号和槽机制、运行时类型信息和动态属性系统都需要元对象代码。
4 来自 Signals and Slots
的 Qt 文档Q_OBJECT 宏被预处理器扩展,声明了几个由 moc 实现的成员函数;如果您收到“未定义对 LcdNumber 的 vtable 的引用”的编译器错误,您可能忘记运行 moc 或在链接命令中包含 moc 输出。
【讨论】:
在带有-E 的 gcc 中,您可以看到扩展的宏。这就是 Q_OBJECT 在 Linux 上的 gcc 上扩展的内容。请注意,这可能取决于平台,并且可能会根据 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 元对象系统提供的其他服务的类定义的私有部分中。
【讨论】:
Q_OBJECT 宏必须出现在从QObject 派生的每个类中。当宏不存在时,您的代码将被巧妙地破坏,并且仅仅因为它恰好编译并不能使其正常。
Q_OBJECT 宏丢失时编译但不起作用的代码示例?
Q_OBJECT 的实现,您会发现它使用了访问说明符。因此,宏是否应该出现在 private、protected 或 public 说明符下是无关紧要的——将它放在类的头部只是惯例。