Qt小知识1.Q_DECLARE_METATYPE和qRegisterMetaType

发布时间 2023-12-08 17:54:05作者: Qt小罗

1 了解Q_DECLARE_METATYPE

Q_DECLARE_METATYPE 是一个Qt宏,用以通知Qt的反射系统关于自定义类型的存在。当使用此宏声明一个类型后,该类型可以在QVariant中使用。QVariant是Qt中用于存储可以包含任意类型的一个“通用”值容器。

Qt 元对象系统不知道非Qt类的存在,因此如果要在QVariant中存储自定义类型,就需要用这个宏声明它。此宏必须在全局作用域中使用,并且用于类型定义之后。它实际上就是为类型定义一个特殊的模板特化,这样QVariant才能了解如何使用它。

这个模板特化提供了一个静态函数qt_metatype_id,它为该类型分配并返回一个独一无二的ID。这个ID用于QVariant创建、复制、比较和析构该类型的实例。

综上,Q_DECLARE_METATYPE(Type)宏用于告诉 Qt 框架某个自定义类型Type是存在的,并且可以被元对象系统所使用。使用这个宏之后,Type就可以用于 QVariant 类型和信号与槽的参数传递中。该宏通常在类的定义外部使用,不需要修改类的定义。注意,仅仅使用Q_DECLARE_METATYPE并不能够在使用信号和槽时动态地创建类型的对象,为此需要使用qRegisterMetaType

struct MyStruct {
    int a;
    QString b;
};

Q_DECLARE_METATYPE(MyStruct)

上述代码使得MyStruct可以被用在 QVariant 内部。

2 了解qRegisterMetaType

qRegisterMetaType 是一个在运行时调用的函数,它将自定义类型注册到Qt的元对象系统中。此函数确保类型不仅已知于QVariant,还已知于Qt的整个类型系统,尤其是用于多线程环境中信号和槽的QObject通信。

注册类型之后,Qt可以动态地在运行时构造和销毁对象,即使是对于非Qt类型。这是因为qRegisterMetaType在内部为类型存储了创建和析构该类型对象所需的方法指针。这允许在运行时创建和复制传递给信号和槽作为参数的类型,这些参数必须能够在事件循环中跨线程边界安全移动。

综上,qRegisterMetaType("TypeName") 函数是在运行时被调用,用于注册类型 Type 到 Qt 的元类型系统。这个步骤是必须的,如果想在信号和槽中,跨线程边界使用该类型。它允许 Qt 知道如何在运行时构造、复制和销毁这种类型的对象。通常这个函数在 main 函数或者类被实际用作信号和槽之前的初始化代码中调用。

int main(int argc, char *argv[]) {
    QApplication app(argc, argv);

    // 注册到元类型系统
    qRegisterMetaType<MyStruct>("MyStruct");

    // 现在 MyStruct 可以安全地用做信号和槽参数
    // ...

    return app.exec();
}

实际应用示例:

如果有一个自定义的类型 MyStruct 并想在不同线程间的信号和槽通信中使用它,需要这么做:

  1. 使用 Q_DECLARE_METATYPE() 声明这个结构体。
struct MyStruct {
    int a;
    QString b;
};

Q_DECLARE_METATYPE(MyStruct)
  1. 在应用程序启动时(例如在 main 函数中),使用 qRegisterMetaType() 来注册自定义类型。
int main(int argc, char *argv[]) {
    QApplication app(argc, argv);

    qRegisterMetaType<MyStruct>("MyStruct");

    // ...
    return app.exec();
}

这使得 MyStruct 可以在跨线程的信号和槽调用中安全使用。如果只是想在同一线程内的信号和槽或者使用 QVariant 存储自定义类型的话,通常只需要 Q_DECLARE_METATYPE 宏。

此外,qRegisterMetaType 还使得自定义类型可用于QMetaObject中的类型信息,比如QObject::property(),QObject::setProperty(),以及QMetaProperty::read()和QMetaProperty::write()这些反射相关的函数。

3 总结

Q_DECLARE_METATYPE 通知Qt元对象系统关于自定义类型的存在,这样该类型就可以在QVariant中使用。qRegisterMetaType在此基础上更进一步,它将自定义类型完全集成到Qt的元对象系统中,使得类型可以跨线程在信号和槽中使用,以及在Qt的属性系统中使用。

了解这两者是如何工作的有助于在Qt应用程序中更有效地使用自定义类型,特别是在需要类型信息的高级特性时,如跨线程信号与槽的通信或属性系统。