Qt小知識1.Q_DECLARE_METATYPE和qRegisterMetaType

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應用程序中更有效地使用自定義類型,特別是在需要類型信息的高級特性時,如跨線程信號與槽的通信或屬性系統。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章