Qt 的元對象係統為對象間通信、運行時類型信息及動態特性係統,提供信號和槽機製。
元對象係統基於 3 件事:
moc
) 供給各
QObject
子類 (采用必要代碼) 以實現元對象特徵。
The
moc
工具讀取 C++ 源文件。若找到一個或多個類聲明包含
Q_OBJECT
宏,它産生包含每個這些類的元對象代碼的另一 C++ 源文件。這生成的源文件將
#include
放入類源文件,或更通常,編譯並鏈接類實現。
除瞭提供 信號/槽 機製用於對象之間的通信 (引入係統的主要原因),元對象代碼提供以下額外特徵:
也可以履行動態鑄造使用
qobject_cast
() 在
QObject
類。
qobject_cast
() 函數行為類似於標準 C++
dynamic_cast()
,它的優點是不要求 RTTI (運行時類型信息) 支持,且工作跨動態庫邊界。它試圖將其自變量鑄造嚮在尖括號中指定的指針類型,返迴非零指針若對象類型正確 (在運行時確定),或
nullptr
若對象類型不兼容。
例如,假定
MyWidget
繼承自
QWidget
和聲明采用
Q_OBJECT
宏:
QObject *obj = new MyWidget;
The
obj
變量,類型
QObject *
,實際引用
MyWidget
對象,因此可以適當鑄造:
QWidget *widget = qobject_cast<QWidget *>(obj);
鑄造從
QObject
to
QWidget
成功,因為對象實際是
MyWidget
,這是子類對於
QWidget
。由於知道
obj
是
MyWidget
,也可以將它鑄造成
MyWidget *
:
MyWidget *myWidget = qobject_cast<MyWidget *>(obj);
鑄造成
MyWidget
成功因為
qobject_cast
() 使在內置 Qt 類型和自定義類型之間沒有區彆。
QLabel *label = qobject_cast<QLabel *>(obj);
// label is 0
鑄造成 QLabel ,在其它方麵,失敗。然後,將指針設為 0。這使基於不同類型在運行時處理不同類型對象,成為可能:
if (QLabel *label = qobject_cast<QLabel *>(obj)) {
label->setText(tr("Ping"));
} else if (QPushButton *button = qobject_cast<QPushButton *>(obj)) {
button->setText(tr("Pong!"));
}
雖然可以使用 QObject 作為基類不用 Q_OBJECT 宏及不用元對象代碼,信號和槽及在此處描述的其它特徵將不可用若 Q_OBJECT 宏不被使用。從元對象係統角度來看, QObject 子類 (沒有元代碼) 相當於具有元對象代碼的其最接近祖先。例如,這意味著 QMetaObject::className () 不會返迴實際類名,但會返迴此祖先的類名。
因此,強烈推薦所有子類化的 QObject 使用 Q_OBJECT 宏,不管它們是否有實際使用信號,槽及特性。
另請參閱 QMetaObject , Qt 的特性係統 ,和 信號和槽 .