原標題:Qt 中的對象模型(Object Model)90不太后,余生皆折騰 本節內容主要講了 Qt 對象模型比標准 C++ 對象模型多了什么內容,並介紹了組成 Qt 對象模型基礎的相關的類。最后說明了為啥 QObject 作為參數時,幾乎都用指針形式的原因。更多內容可參考官方文檔 Object Model。
我們使用的標准 C++,其設計的對象模型雖然已經提供了非常高效的 RTTI 支持,但是在某些方面還是不夠靈活。比如在 GUI 編程方面,既需要高效的運行效率也需要強大的靈活性,諸如刪除某窗口時可不想把子窗口用代碼一個個去析構。Qt 將這兩者的優點完美的結合在了一起,創造出了特有的對象模型(Qt Object Model)。
利用這個對象模型,Qt 語言可比 C++ 提供了更多的功能,使用起來相當的方便。那么只有 Qt 有而 C++ 沒有的特性有:方便兩個對象間交互的“信號-槽”機制非常靈活好用的“對象屬性系統”可以使用強大的“事件及事件過濾”可以國際化翻譯字符串可以在 GUI 編程中用 Qt 提供的“計時器”完成許多任務以一種自然的方式組織對象父子關系的“對象樹”當引用對象被銷毀時會自動設為0的指針(主要是 QPointer),而 C++ 指針銷毀時將成為懸空指針Qt 對象之間的動態轉換支持可以自定義創建一個 Qt 類型,從而享受 Qt 的其他特性
在繼承 QObject 類的基礎上,一些 Qt 特性是用 C++ 實現的,一些 Qt 特性(如信號槽、對象屬性)是依靠 Qt 的元對象系統以及 moc工具 實現。
其實,相比 C++ 來說,最大的優點就是元對象系統,真是太強大了。和對象模型相關的類
以下類構成了 Qt 對象模型的基礎。
QObject 的特殊性
上文提到的新增特性,我們需要將 Qt 對象視為 ID,而不是數值。數值被復制后還是原來的值,ID 被復制了需要指定新的唯一標識。舉個生活中的例子就是,雙胞胎的數值一樣,但是 ID 不同。
禁用拷貝構造函數、禁用賦值運算符
分配新的 ID 可比賦值要復雜的多,我們可以看下這對於 Qt 來說意味着什么:Qt 對象有唯一的 QObject::objectName(),復制一個 Qt 對象我們需要起個什么新名字呢?Qt 對象在對象樹中有一個位置,被復制后副本放在哪個層次的哪個位置?Qt 對象被復制后,原有的信號槽連接如何轉移到副本?Qt 對象被復制后,運行時的副本是否包含新增加的屬性值?
所以QObject及其子類都禁用了復制構造函數和賦值運算符。
不能用復制構造函數示例,錯誤示范:QObjectx;QObjecty(x);
不能用賦值運算符示例,錯誤示范:QObject x;QObject y; y = x;
編程中的影響
這樣做的結果就是,開發者在某些場景下需要使用 QObject 作為“值”時,必須使用指針傳遞,而不能用值傳遞。
我們知道在各種容器中能以value方式存放的類型,必須有默認的構造函數,拷貝構造函數和賦值操作。由於 QObject 及子類不能拷貝和賦值,當我們使用 QList<QObject> 時,編譯器就會報錯。如果我們要在容器中存儲這中類型的對象,我們就要使用它們的指針。如 QList<QObject *>。