Qt的元對(duì)象系統(tǒng)提供了對(duì)象間通信的信號(hào)和槽機(jī)制、運(yùn)行時(shí)類(lèi)型信息和動(dòng)態(tài)屬性系統(tǒng)。就是動(dòng)態(tài)的獲取一些對(duì)象屬性之類(lèi)的,我經(jīng)常會(huì)用到。
元對(duì)象系統(tǒng)基于三件事:
這個(gè)就是要求我們?cè)趯?xiě)自己的類(lèi)的時(shí)候要繼承 自 QObject 同時(shí)添加 Q_OBJECT 宏就好。
moc工具讀取 c++ 源文件。如果它找到一個(gè)或多個(gè)包含 Q_OBJECT 宏的類(lèi)聲明,它會(huì)生成另一個(gè)包含每個(gè)類(lèi)的元對(duì)象代碼的c++源文件。這個(gè)生成的源文件要么 #include 到類(lèi)的源文件中,要么,更常見(jiàn)的是,編譯并鏈接到類(lèi)的實(shí)現(xiàn)。
除了提供對(duì)象之間通信的信號(hào)和槽機(jī)制(引入該系統(tǒng)的主要原因),元對(duì)象代碼還提供了下列額外功能。
QObject *obj = new QPushButton;
obj->metaObject()->className(); // returns "QPushButton"
QPushButton::staticMetaObject.className(); // returns "QPushButton"
QTimer *timer = new QTimer; // QTimer inherits QObject
timer->inherits("QTimer"); // returns true
timer->inherits("QObject"); // returns true
timer->inherits("QAbstractButton"); // returns false
// QVBoxLayout inherits QObject and QLayoutItem
QVBoxLayout *layout = new QVBoxLayout;
layout->inherits("QObject"); // returns true
layout->inherits("QLayoutItem"); // returns true (even though QLayoutItem is not a QObject)
還可以使用 qobject_cast() 對(duì)QObject類(lèi)執(zhí)行動(dòng)態(tài)強(qiáng)制轉(zhuǎn)換。qobject_cast( )函數(shù)的行為類(lèi)似于標(biāo)準(zhǔn)c++ dynamic_cast(),其優(yōu)點(diǎn)是它不需要RTTI支持,并且可以跨動(dòng)態(tài)庫(kù)邊界工作。它嘗試將其參數(shù)轉(zhuǎn)換為尖括號(hào)中指定的指針類(lèi)型,如果對(duì)象的類(lèi)型正確(在運(yùn)行時(shí)確定),則返回一個(gè)非零指針,如果對(duì)象的類(lèi)型不兼容,則返回nullptr。
例如,假設(shè)MyWidget繼承自QWidget,并用Q_OBJECT宏聲明:
QObject *obj = new MyWidget;
類(lèi)型為QObject *的obj變量實(shí)際上引用了一個(gè)MyWidget對(duì)象,因此我們可以適當(dāng)?shù)匦U?
QWidget *widget = qobject_cast(obj);
從QObject轉(zhuǎn)換到QWidget是成功的,因?yàn)閷?duì)象實(shí)際上是一個(gè)MyWidget,它是QWidget的子類(lèi)。因?yàn)槲覀冎纎bj是一個(gè)MyWidget,我們也可以將它強(qiáng)制轉(zhuǎn)換為MyWidget *:
MyWidget *myWidget = qobject_cast(obj);
轉(zhuǎn)換到MyWidget是成功的,因?yàn)閝object_cast()沒(méi)有區(qū)分內(nèi)置Qt類(lèi)型和自定義類(lèi)型。
QLabel *label = qobject_cast(obj);
// label is 0
另一方面,轉(zhuǎn)換為QLabel會(huì)失敗。接下來(lái),該指針設(shè)置為0。這使得可以在運(yùn)行時(shí)根據(jù)類(lèi)型以不同的方式處理不同類(lèi)型的對(duì)象:
if (QLabel *label = qobject_cast(obj))
{ label->setText(tr("Ping"));
} else if (QPushButton *button = qobject_cast(obj))
{ button->setText(tr("Pong!"));
}
雖然可以在沒(méi)有Q_OBJECT宏和元對(duì)象代碼的情況下使用QObject作為基類(lèi),但如果沒(méi)有使用Q_OBJECT宏,則信號(hào)和插槽以及這里描述的其他功能都不可用。從元對(duì)象系統(tǒng)的角度來(lái)看,沒(méi)有元代碼的QObject子類(lèi)等同于它有元對(duì)象代碼的最近的祖先。這意味著,例如,QMetaObject::className()不會(huì)返回你的類(lèi)的實(shí)際名稱,而是這個(gè)祖先的類(lèi)名。
因此,我們強(qiáng)烈建議QObject的所有子類(lèi)使用Q_OBJECT宏,無(wú)論它們是否實(shí)際使用信號(hào)、槽和屬性。
你是否還在尋找穩(wěn)定的海外服務(wù)器提供商?創(chuàng)新互聯(lián)www.cdcxhl.cn海外機(jī)房具備T級(jí)流量清洗系統(tǒng)配攻擊溯源,準(zhǔn)確流量調(diào)度確保服務(wù)器高可用性,企業(yè)級(jí)服務(wù)器適合批量采購(gòu),新人活動(dòng)首月15元起,快前往官網(wǎng)查看詳情吧