Qt元對象系統簡介
在Qt中提供了c++的擴展,提供了一種元對象系統的機制,(meta-object-system)的機制。其中包含了信號與槽的內部機制,能夠訪問到QObject子類的元對象信息的功能。
Q_OBJECT 宏聲明了在每一個QObject子類中必須首選的內省函數:metaObject(),tr(),qt_metacall()以及其他一些函數
Qt的moc工具生成了用於Q_OBJECT聲明的所有函數和所有信號的實現
同時也提供了connect()和disconnect()這樣的內省函數
Qt 不使用標準的C++語言,而是進行了一定程度的擴展,增加了一些新的關鍵字(例如 signals、slots、emit 等),並實現了反射(內省)機制。
我們知道,
雖然C++提供了RTTI機制,但非常簡陋,對象被創建後僅能獲得類的名字,這使得RTTI不堪重用,如同雞肋。像Java、C#等面向對象的語言,可以通過對象完整還原出類的信息,例如類的名字、父類、類所包含的成員變量和成員函數以及它們的修飾符等。這被稱作反射機制或內省機制,也就是說對象可以認知自己。
反射機制無疑會增加額外的存儲空間,在效率上有所犧牲,而且在普通程序中沒有用武之地,為了保持幾乎與
但對於大型框架或類庫來說,反射機制有時很有必要,它會增加程序的靈活性和動態性,例如動態加載類、解耦等。最明顯的一個例子是編譯器的智能提示,當輸入完對象的名稱,再輸入.或->,就會提示該對象擁有的變量和函數,這是反射機制的典型應用。
如今,C++的反射機制在 Qt、Boost 等框架中的實現已經非常成熟。
moc
Qt 在將源代碼交給標準C++編譯器之前,例如GCC、VS等,需要提前將這些擴展的語法去除掉。完成這一操作的就是 moc。
moc 全稱是"Meta-Object Compiler",也就是”元對象編譯器“。moc 就是一個源代碼分析程序,它會讀取C++源文件,如果發現在一個頭文件中包含了宏 Q_OBJECT,則會生成另外一個C++源文件。這個源文件中包含了 Q_OBJECT 宏的實現代碼。這個新文件的名字將由源文件名加上moc_前綴構成,讀者可以在
新文件並不會替換舊文件,而是與舊文件一起進入編譯系統,最終被鏈接到二進制代碼中去。
可以發現,moc 的執行在C++預處理器之前,因為預處理器執行之後會進行宏替換,Q_OBJECT 就不存在了。
元對象系統
Qt中的元對象系統是用來處理對象間通訊的信號/槽機制、運行時的類型信息和 動態屬性系統。
它基於下列三類:
- QObject類;為所有需要利用原對象系統的對象提供了一個基類。
- 類聲明中的私有段中的Q_OBJECT宏;通常可以聲明在類的私有段中,讓該類可以使用元對象的特性,比如動態屬性,信號和槽。
- 元對象編譯器(moc)。元對象編譯器(moc)為每個QObject子對象自動生成必要的代碼來實現元對象特性。
moc讀取C++源文件。如果它發現其中包 含一個或多個類的聲明中含有Q_OBJECT宏,它就會給含有Q_OBJECT宏的類生成另一個 含有元對象代碼的C++源文件。這個生成的源文件可以被類的源文件包含(#include) 到或者和這個類的實現一起編譯和連接。
除了提供對象間通訊的信號和槽機制之 外(介紹這個系統的主要原因),QObject中的元對象代碼還提供以下特征:
- className()函數在運行的時候以 字符串返回類的名稱,不需要C++編譯器中的本地運行類型信息(RTTI)的支持。
- inherits()函數返回這個對象是否 是一個繼承於QObject繼承樹中一個特定類的類的實例。
- tr()和trUtf8() 兩個函數是用於國際化中的字符串翻譯。
- setProperty()和property()兩個函數是用來通過名稱動態設置和 獲得對象屬性的。
- metaObject()函數返回這個類 所關聯的元對象。
雖然你使用QObject作為一個基類而不使用Q_OBJECT宏和元對象代碼是可以的, 但是如果Q_OBJECT宏沒有被使用,那麽這裏的信號和槽以及其它特征描述都不會被 提供。根據元對象系統的觀點,一個沒有元代碼的QObject的子類和它含有元對象代 碼的最近的祖先相同。舉例來說就是,className()將不會返回你的類的實際名稱, 返回的是它的這個祖先的名稱。我們強烈建議QObject 的所有子類使用Q_OBJECT宏,而不管它們是否實際使用了信號、槽和屬性
http://blog.csdn.net/tingsking18/article/details/4800828
Qt元對象系統簡介