元對象係統

Qt 的元對象係統為對象間通信、運行時類型信息及動態特性係統,提供信號和槽機製。

元對象係統基於 3 件事:

  1. The QObject 類為可以利用元對象係統的對象提供基類。
  2. The Q_OBJECT 宏 (在類聲明私有區間內) 用於啓用元對象特徵,譬如:動態特性、信號及槽。
  3. The Meta-Object Compiler ( 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 的特性係統 ,和 信號和槽 .