一、Meta-Object簡(jiǎn)介
Meta-Object即是Qt的元對(duì)象系統(tǒng),下文都以元對(duì)象系統(tǒng)進(jìn)行描述。在Qt中,具有標(biāo)志性特征的則是信號(hào)和槽函數(shù)機(jī)制,該機(jī)制的背后實(shí)現(xiàn)本質(zhì)上則是元對(duì)象系統(tǒng)。編寫Qt代碼的時(shí)候,在定義類的時(shí)候,需要放置一個(gè)Q_OBJECT,為什么呢?后文會(huì)描述到,例如如下代碼:
image-20230207220020441
Q_OBJECT本質(zhì)上是一個(gè)宏定義,在進(jìn)行Qt開發(fā)時(shí),所有QObject的派生類都推薦在頭文件中放置Q_OBJECT宏定義,該宏定義如下(出自qobjectdefs.h文件):
#defineQ_OBJECT public: QT_WARNING_PUSH Q_OBJECT_NO_OVERRIDE_WARNING staticconstQMetaObjectstaticMetaObject; virtualconstQMetaObject*metaObject()const; virtualvoid*qt_metacast(constchar*); virtualintqt_metacall(QMetaObject::Call,int,void**); QT_TR_FUNCTIONS private: Q_OBJECT_NO_ATTRIBUTES_WARNING Q_DECL_HIDDEN_STATIC_METACALLstaticvoidqt_static_metacall(QObject*,QMetaObject::Call,int,void**); QT_WARNING_POP structQPrivateSignal{}; QT_ANNOTATE_CLASS(qt_qobject,"")
Qt中,元對(duì)象系統(tǒng)包含了支持元對(duì)象系統(tǒng)的程序,宏定義,基類,接口函數(shù)。這些東西共同構(gòu)成了Qt的元對(duì)象系統(tǒng):
(1)QObject為想要使用元對(duì)象系統(tǒng)的對(duì)象提供了基類。
(2)Q_OBJECT宏用于啟動(dòng)元對(duì)象特性,例如:動(dòng)態(tài)屬性、信號(hào)和槽函數(shù)機(jī)制等。
(3)元對(duì)象編譯器(moc)為每個(gè)QObject子類生成實(shí)現(xiàn)元對(duì)象特性所需要的代碼。
在實(shí)際Qt程序設(shè)計(jì)中,在派生自QObject的類定義中加上Q_OBJECT后,則可以使用元對(duì)象系統(tǒng)所支持的特性了。
二、元對(duì)象系統(tǒng)背后機(jī)制
如果在派生自QObject的類定義中加上了Q_OBJECT后,在編譯構(gòu)建過程中,元對(duì)象系統(tǒng)的moc工具(本文以Windows平臺(tái)為例,該工具則位于具體Qt版本目錄下的bin目錄中)
在Windows命令行下運(yùn)行,可獲知如下信息:
在QtCreator集成開發(fā)環(huán)境中,當(dāng)點(diǎn)擊構(gòu)建按鈕后,QtCreator會(huì)自動(dòng)調(diào)用moc工具,該工具會(huì)讀取一個(gè)C++源文件,如果它發(fā)現(xiàn)一個(gè)或多個(gè)包含Q_OBJECT宏的類聲明,那么則會(huì)生成另外一個(gè)C++源文件,源文件中包含每個(gè)類的元對(duì)象代碼。接著,生成的源文件要么被#include包含到類的源文件中,要么被編譯并鏈接到類的實(shí)現(xiàn)中。例如下列一個(gè)簡(jiǎn)單的項(xiàng)目工程,源碼結(jié)構(gòu)如下:
從上圖可知,工程中包含了一個(gè)main.cpp、一個(gè)主窗口描述文件mainwindow.cpp/.h、一個(gè)stylesheeteditor.cpp/.h文件,由于mainwindow.cpp/.h、stylesheeteditor.cpp/.h支持Qt的元對(duì)象系統(tǒng),在編譯構(gòu)建過程中,則會(huì)生成支持元對(duì)象系統(tǒng)的中間文件,如下圖所示:
從上圖可知,這些文件都以moc_xxx方式進(jìn)行命名,最后結(jié)合其他的文件生成了程序可執(zhí)行體(stylesheet.exe),整個(gè)過程可如下圖所示(Windows平臺(tái)):
三、再談元對(duì)象系統(tǒng)
除了提供對(duì)象之間通信的信號(hào)和槽函數(shù)機(jī)制(這是引入該系統(tǒng)的主要原因),元對(duì)象系統(tǒng)還提供以下的功能:
(1)Object::metaObject():返回類的關(guān)聯(lián)元對(duì)象。
(2)QMetaObject::className():在運(yùn)行時(shí)以字符串的形式返回類名,而不需要通過C++編譯器提供本地運(yùn)行時(shí)類型信息(RTTI)支持。
(3)QObject::inherits():函數(shù)返回一個(gè)對(duì)象是否是在QObject繼承樹中繼承指定類實(shí)例。
(4)QObject::tr()和QObject::trUtf8()為國(guó)際化翻譯字符串。
(5)QObject::setProperty()和QObject::property()根據(jù)名稱動(dòng)態(tài)設(shè)置和獲取屬性。
(6)QMetaObject::newInstance():構(gòu)造類的新實(shí)例。
除了上述所列的功能,還可以使用qobject_cast()對(duì)QObject類執(zhí)行動(dòng)態(tài)強(qiáng)制類型轉(zhuǎn)換,qobject_cast()函數(shù)的行為類似于標(biāo)準(zhǔn)C++ 的dynamic_cast(),它的優(yōu)點(diǎn)是不需要RTTI支持,并且可以跨動(dòng)態(tài)庫工作。該函數(shù)嘗試將其參數(shù)轉(zhuǎn)換為尖括號(hào)中指定的指針類型,如果對(duì)象的類型正確(在運(yùn)行時(shí)確定),則返回非零指針;如果對(duì)象的類型不兼容,則返回nullptr。
例如,假設(shè)有一個(gè)MyWidget繼承自QWidget,并使用了Q_OBJECT宏聲明,然后使用new創(chuàng)建該實(shí)例:
QObject*obj=newMyWidget;
類型為QObject *的obj變量實(shí)際上引用了一個(gè)MyWidget對(duì)象,所以我們可以對(duì)它進(jìn)行適當(dāng)?shù)念愋娃D(zhuǎn)換,如下代碼:
QWidget*widget=qobject_cast(obj);
從QObject到QWidget的轉(zhuǎn)換是成功的,因?yàn)樵搶?duì)象實(shí)際上是一個(gè)MyWidget,它是QWidget的一個(gè)子類。既然知道obj是一個(gè)MyWidget,我們也可以將它c(diǎn)ast到MyWidget *,如下代碼:
MyWidget*myWidget=qobject_cast(obj);
上述代碼對(duì)MyWidget的轉(zhuǎn)換是也成功的,因?yàn)閝object_cast()在內(nèi)置Qt類型和自定義類型之間沒有區(qū)別。
然而對(duì)于下列代碼:
QLabel*label=qobject_cast(obj);
對(duì)QLabel的強(qiáng)制轉(zhuǎn)換將失敗,會(huì)將指針設(shè)置為0。因此可以在運(yùn)行時(shí)處理不同類型的對(duì)象,例如:
if(QLabel*label=qobject_cast(obj)) { label->setText(tr("iriczhao")); } elseif(QPushButton*button=qobject_cast (obj)) { button->setText(tr("嵌入式小生")); }
上述代碼使用qobject_case()對(duì)obj進(jìn)行了向QLabel和QPushButton的強(qiáng)制轉(zhuǎn)換,如果轉(zhuǎn)換成功,則設(shè)置對(duì)應(yīng)的顯示文本。
四、小生總結(jié)
在實(shí)際Qt開發(fā)過程中,雖然可以在沒有Q_OBJECT宏和元對(duì)象代碼的情況下將QObject作為基類,但如果沒有使用Q_OBJECT宏,則信號(hào)和槽函數(shù)機(jī)制或在本文中描述的其他特性都不能使用。從元對(duì)象系統(tǒng)的角度來看,一個(gè)沒有元代碼的QObject子類等價(jià)于它最近的有元對(duì)象代碼的祖先。這意味著,例如,QMetaObject::className()將不會(huì)返回自己類的實(shí)際名稱,而是這個(gè)祖先的類名稱。
因此,在實(shí)際Qt開發(fā)過程中,無論實(shí)際上是否使用了信號(hào)和槽函數(shù)機(jī)制,都強(qiáng)烈建議QObject的所有子類都使用Q_OBJECT宏。
審核編輯:湯梓紅
-
函數(shù)
+關(guān)注
關(guān)注
3文章
4327瀏覽量
62569 -
代碼
+關(guān)注
關(guān)注
30文章
4779瀏覽量
68521 -
Meta
+關(guān)注
關(guān)注
0文章
270瀏覽量
11378 -
編譯器
+關(guān)注
關(guān)注
1文章
1623瀏覽量
49108 -
Qt
+關(guān)注
關(guān)注
1文章
302瀏覽量
37899
原文標(biāo)題:Qt“靈魂”之Meta-Object系統(tǒng)
文章出處:【微信號(hào):嵌入式小生,微信公眾號(hào):嵌入式小生】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。
發(fā)布評(píng)論請(qǐng)先 登錄
相關(guān)推薦
評(píng)論