【问题标题】:What does the Q_OBJECT macro do? Why do all Qt objects need this macro?Q_OBJECT 宏有什么作用?为什么所有 Qt 对象都需要这个宏?
【发布时间】:2010-11-25 00:16:26
【问题描述】:

我刚开始使用 Qt,注意到所有示例类定义的第一行都有宏 Q_OBJECT。这个预处理器宏的用途是什么?

【问题讨论】:

  • QT 指的是 QuickTime,Qt 指的是名为 Qt 的 C++ 库。

标签: c++ qt macros


【解决方案1】:

来自Qt documentation

元对象编译器 moc 是 处理 Qt 的 C++ 的程序 扩展。

moc 工具读取 C++ 头文件。 如果它找到一个或多个类 包含 Q_OBJECT 的声明 宏,它产生一个 C++ 源文件 包含元对象代码 那些课。除其他事项外, 元对象代码是必需的 信号和槽机制, 运行时类型信息,以及 动态属性系统。

【讨论】:

  • 为什么我不需要明确写Q_OBJECT::connect() 而只是connect()
  • @mLstudent33 如果你愿意,你可以写 QObject::connect()。
【解决方案2】:

它只是告诉预编译器这个类需要通过'moc'或元对象编译器运行,它为类添加额外的隐藏字段和函数以及解析信号和槽。您只需要将它添加到使用信号/槽机制或其他 Qt 类级别功能(例如自省)的类中。您不需要将 Q_OBJECT 添加到仅使用标准 C++ 功能的类。

【讨论】:

  • 仅在使用信号/槽机制的类上才需要它也是错误的。 Q_OBJECT 的缺席打破了qobject_cast 和自省。它可能会导致一些令人困惑的行为,所以这是一个坏主意。
  • Q_OBJECT 不会在任何其他(非QObject)类中被“悄悄地”忽略。根据 C++ 标准,它通过声明几个从未定义的成员函数和变量来引入未定义的行为。它还会用QObject 特定的成员污染你的类的命名空间。例如。 Q_OBJECT 很可能会破坏恰好包含名为 metaObject 的方法的无关类。
  • 错了。尽管您可能希望为大多数 gui 类配备 Q_OBJECT 宏,但将非 gui 类与宏以及没有宏的 gui 类一起使用是非常有意义的。该宏很有用,但不仅限于 gui 类,也不是必需的。
【解决方案3】:

MOC(元对象编译器)将 Q_OBJECT 宏包含的头文件转换为 C++ 等效源代码。 它基本上控制了信号槽机制,并使 C++ 编译器可以理解

【讨论】:

  • 那是错误的:Q_OBJECT 宏由编译器扩展,不需要 moc。 moc 不对宏本身做任何事情,但它生成Q_OBJECT 宏已声明的成员变量和方法的定义
【解决方案4】:

1 来自 The Meta-Object System

的 Qt 文档

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 输出。

【讨论】:

    【解决方案5】:

    在带有-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 {};
    

    【讨论】:

      【解决方案6】:

      Q_OBJECT 宏必须出现在声明自己的信号和槽或使用 Qt 元对象系统提供的其他服务的类定义的私有部分中。

      【讨论】:

      • 这是一种误导:Q_OBJECT 宏必须出现在从QObject 派生的每个类中。当宏不存在时,您的代码将被巧妙地破坏,并且仅仅因为它恰好编译并不能使其正常。
      • @KubaOber 你有没有在Q_OBJECT 宏丢失时编译但不起作用的代码示例?
      • 如果您查看Q_OBJECT 的实现,您会发现它使用了访问说明符。因此,宏是否应该出现在 privateprotectedpublic 说明符下是无关紧要的——将它放在类的头部只是惯例。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-03-03
      • 1970-01-01
      相关资源
      最近更新 更多