1. 程式人生 > >Qt元物件系統

Qt元物件系統

元物件系統

系統介紹

Qt 元物件系統(Meta-Object System)

Qt的元物件系統基於如下三件事情:

1. 類:QObject,為所有需要利用元物件系統的物件提供了一個基類。

2. 巨集:Q_OBJECT,通常可以宣告在類的私有段中,讓該類可以使用元物件的特性,比如動態屬性,訊號和槽。

3. 編譯器:元物件編譯器(moc)為每個QObject子物件自動生成必要的程式碼來實現元物件特性。

moc工具會讀入C++的原始檔,如果它發現了一個或者多個聲明瞭Q_OBJECT巨集的類,它就建立另一個C++原始檔,為每個類生成包含元物件實現的程式碼。這些編譯生成的原始檔通常都已經被包含到類的原始檔中或者和類的實現同時被編譯和連結。

除了為物件間的通訊提供訊號和槽(signals and slots)機制之外,元物件的程式碼還提供下列特性:

· QObject::metaObject()返回與該類繫結的meta-object物件。

· QMetaObject::className()可以在執行時以字串的形式返回類的名字,不需要C++編譯器原生的執行時型別資訊(RTTI)的支援。

· QObject::inherits()函式返回繼承資訊:物件是否是QObject繼承樹上一個類的例項。

· QObject::tr()和QObject::trUtf8()提供國際化支援,將字串翻譯成指定的語言。

· QObject::setProperty()和QObject::property()通過名字動態設定和獲取物件屬性。

· QMetaObject::newInstance()構造該類的一個新例項。

除此之外你還可以用qobject_cast()動態轉換QObject類的型別。qobject_cast()函式和標準C++的dynamic_cast()功能類似,只是其不需要RTTI的支援,而且可以跨越動態連線庫的邊界。它嘗試將它的引數cast成尖括號內的物件型別,如果物件是正確的型別(執行時決定)則返回非零,否則返回0,說明物件型別不相容。

例如,假設MyWidget繼承自QWidget,同時也聲明瞭Q_OBJECT巨集,

QObject *obj = new MyWidget;QObject型別的變數obj實際上指向一個MyWidget物件,因此我們可以這樣進行型別轉換:

QWidget *widget = qobject_cast<QWidget *>(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!")); }儘管我們可以在不用Q_OBJECT巨集和原物件資訊的情況下仍舊使用QObject作為基類,但是像訊號和槽以及其他這裡描述的特性將無法使用。從元物件系統的觀點來看,一個沒有元物件程式碼的QObject子類和其最接近的有元物件程式碼的祖先是等同的。這也就意味著,QMetaObject::className()將不會返回你的類的真實的名字,而是該類某一個祖先的名字。

因此,我們強烈建議所有QObject的子類都是用Q_OBJECT巨集,不管你實際上是否使用訊號和槽,以及屬性