? ? ? Qt的元對象系統(Meta-Object System)提供了對象間通信的信號和槽機制、運行時類型信息和動態屬性系統。
? ? ? 元對象系統基于以下三個方面:
? ? ? (1).QObject類:為可以利用元對象系統的對象提供了基類。
? ? ? (2).Q_OBJECT宏:用于啟用元對象功能,例如動態屬性、信號和槽。Q_OBJECT宏內容如下:
#define Q_OBJECT \
public: \QT_WARNING_PUSH \Q_OBJECT_NO_OVERRIDE_WARNING \static const QMetaObject staticMetaObject; \virtual const QMetaObject *metaObject() const; \virtual void *qt_metacast(const char *); \virtual int qt_metacall(QMetaObject::Call, int, void **); \QT_TR_FUNCTIONS \
private: \Q_OBJECT_NO_ATTRIBUTES_WARNING \Q_DECL_HIDDEN_STATIC_METACALL static void qt_static_metacall(QObject *, QMetaObject::Call, int, void **); \QT_WARNING_POP \struct QPrivateSignal { explicit QPrivateSignal() = default; }; \QT_ANNOTATE_CLASS(qt_qobject, "")
? ? ? (3).元對象編譯器(Meta-Object Compiler, MOC):為每個QObject子類提供實現元對象功能所需的代碼。
? ? ? MOC工具讀取(reads) C++源文件。如果它發現一個或多個包含Q_OBJECT宏的類聲明,它會生成另一個C++源文件,其中包含每個類的元對象代碼(meta-object code)。生成的源文件要么被 #include到類的源文件中,要么更常見的是,被編譯并與類的實現鏈接。
? ? ? 通過MOC工具由mainwindow.h生成moc_mainwindow.cpp,內容類似如下圖所示:信號函數的實現也在此文件中;生成此.cpp文件對應的CMake命令為qt6_wrap_cpp
? ? ? 元對象代碼除了提供對象間通信的信號和槽機制(引入該系統的主要原因)外,還提供以下附加功能:
? ? ? (1).QObject::metaObject():返回與該類相關的元對象。
? ? ? (2).QMetaObject::className():在運行時以字符串形式返回類名,無需通過C++編譯器支持本機運行時類型信息(run-time type information, RTTI)。
? ? ? (3).QObject::inherits():函數返回某個對象是否是繼承QObject繼承樹中指定類的類的實例。
? ? ? (4).QObject::tr():翻譯字符串以實現國際化(internationalization)。
? ? ? (5).QObject::setProperty():通過名稱動態設置屬性。
? ? ? (6).QObject::property():通過名稱動態獲取屬性。
? ? ? (7).QMetaObject::newInstance():構造該類新實例。
? ? ? qobject_cast():可以使用qobject_cast()對QObject類執行動態轉換。qobject_cast()函數的行為類似于標準C++ dynamic_cast(),其優點是它不需要RTTI支持,并且可以跨動態庫邊界(dynamic library boundaries)工作。它嘗試將其參數轉換為尖括號中指定的指針類型,如果對象是正確的類型(在運行時確定),則返回非零指針,如果對象的類型不兼容,則返回nullptr。
? ? ? 雖然可以使用QObject作為基類,而無需Q_OBJECT宏和元對象代碼,但如果不使用Q_OBJECT宏,則信號和槽以及上面描述的其他功能都將不可用。從元對象系統的角度來看,沒有元代碼的QObject子類相當于其具有元對象代碼的最近祖先(closest ancestor)。這意味著,例如,QMetaObject::className()將不會返回你的類的實際名稱,而是返回此祖先的類名。
? ? ? 強烈建議QObject的所有子類都使用Q_OBJECT宏,無論它們是否實際使用信號、槽和屬性。
? ? ? QMetaObject類:包含有關Qt對象的元信息(meta-information)。
? ? ? (1).Qt中的元對象系統負責信號和槽對象間通信機制、運行時類型信息和Qt屬性系統。為應用程序中使用的每個QObject子類創建一個QMetaObject實例,此實例存儲 QObject子類的所有元信息。此對象可用作QObject::metaObject()。
? ? ? (2).此類通常不是應用程序編程所必需的,但如果你編寫元應用程序(例如腳本引擎或GUI構建器),它會很有用。
? ? ? (3).使用元對象系統的操作通常是線程安全的,因為QMetaObjects通常是編譯時生成的靜態只讀實例(static read-only instances)。但是,如果應用程序動態修改元對象(例如,使用QQmlPropertyMap時),則應用程序必須明確同步對相應元對象的訪問。
? ? ? 注:以上整理的內容主要來自于Qt官方文檔
? ? ? GitHub:https://github.com/fengbingchun/Qt_Test