如何 Qt用模板來(lái)實(shí)現(xiàn)信號(hào)和槽
如何Qt用模板來(lái)實(shí)現(xiàn)信號(hào)和槽是本文介紹的內(nèi)容,之前我們也介紹過(guò)關(guān)于信號(hào)與槽的一些文章,想要獲取更多資料,請(qǐng)看末尾?,F(xiàn)在我們先來(lái)看內(nèi)容。
一個(gè)簡(jiǎn)單的答案是,當(dāng)初Qt 被設(shè)計(jì)的時(shí)候,因?yàn)楦鞣N各樣的編譯器的不充分,所以在多平臺(tái)應(yīng)用程序中完全使用模板機(jī)制是不可能的。甚至今天,許多被廣泛使用的C++編譯器在使用高級(jí)模板的時(shí)候還是有問(wèn)題的。例如,你不能安全地依靠部分模板的示例,這對(duì)一些不平常的問(wèn)題領(lǐng)域是必要的。因此Qt 中模板的用法不得不保守。記住Qt 是一個(gè)多平臺(tái)的工具包,在Linux/g++平臺(tái)上的進(jìn)步不一定能夠在其它情況下獲得改進(jìn)。
那些在模板執(zhí)行上比較弱的編譯器終將得到改進(jìn)。但是,即使我們所有的用戶以極好的模板支持接近一個(gè)完全現(xiàn)代的C++編譯器的標(biāo)準(zhǔn),我們也不會(huì)放棄通過(guò)使用我們的元對(duì)象編譯器的基于字符串的途徑。這里是為什么這樣做的五個(gè)原因:
1、語(yǔ)法問(wèn)題
語(yǔ)法不是糖:我們用來(lái)表達(dá)我們的運(yùn)算法則的語(yǔ)法較大程度上影響我們的代碼的可讀性和可維護(hù)性。Qt中信號(hào)和槽所用的語(yǔ)法在實(shí)踐中被證明是非常成功的。這種語(yǔ)法是直觀的、容易使用的和容易讀的。人們?cè)趯W(xué)習(xí)Qt時(shí)發(fā)現(xiàn)這種語(yǔ)法幫助他們理解和使用信號(hào)和槽的概念——而不管它們的高度抽象和通用的性質(zhì)。此外,在類定義中信號(hào)聲明保證了信號(hào)就像被保護(hù)的C++成員函數(shù)一樣被保護(hù)。這幫助了程序員在剛開(kāi)始的時(shí)候就獲得了他們的設(shè)計(jì)權(quán)力,而不用不得不考慮設(shè)計(jì)模式。
2、預(yù)編譯程序是好的
Qt的moc(元對(duì)象編譯器)提供了一種的方式除了那些編譯語(yǔ)言的工具。它可以生成任何一個(gè)標(biāo)準(zhǔn)的C++編譯器都能編譯的額外的C++代碼。元對(duì)象編譯器讀取C++源文件。如果它發(fā)現(xiàn)其中有一個(gè)或多個(gè)類的聲明中含有“Q_OBJECT”這個(gè)宏,它就會(huì)為這些類生成另外一個(gè)包含元對(duì)象代碼的C++源文件。這個(gè)由元對(duì)象編譯器生成的C++源文件必須和它的類實(shí)現(xiàn)一起編譯和連接(或者它也可以被#included到個(gè)類的源文件中)。有特色的是元對(duì)象編譯器不是用手工來(lái)調(diào)用的,它可以自動(dòng)地被連編系統(tǒng)調(diào)用,所以它不需要程序員額外的付出努力。
這里有一些其它的預(yù)編譯程序,比如,rpc和idl,它們使程序或者對(duì)象能夠通過(guò)進(jìn)程或者 machine boundaries來(lái)進(jìn)行通訊。預(yù)編譯程序的選擇是編寫(xiě)編譯器,專有的語(yǔ)言或者使用對(duì)話框或向?qū)н@些圖形編程工具來(lái)生成晦澀的代碼。我們能使我們的客戶使用他們所喜歡的工具,而不是把他們鎖定在一個(gè)專有的C++編譯器或者一個(gè)特殊的集成開(kāi)發(fā)環(huán)境。我們不強(qiáng)迫程序員把生成的代碼添加到源程序倉(cāng)庫(kù)中,而是鼓勵(lì)他們把我們的工具加入到他們的連編系統(tǒng)中:更加干凈,更加安全和更加富有UNIX精神。
3、靈活性為王
C++是一種標(biāo)準(zhǔn)化的、強(qiáng)大的和精心制作的多用途語(yǔ)言。它只是用來(lái)開(kāi)發(fā)很多領(lǐng)域的軟件項(xiàng)目的一種語(yǔ)言,生成許多種應(yīng)用程序,從整個(gè)操作系統(tǒng)、數(shù)據(jù)庫(kù)服務(wù)器和高性能的圖形應(yīng)用程序到普通的桌面應(yīng)用程序。C++成功的關(guān)鍵之一是它著重于最大效能和最小內(nèi)存占用同時(shí)保持ANSI-C的的兼容性的可伸縮語(yǔ)言設(shè)計(jì)
在這些優(yōu)勢(shì)當(dāng)中,也有一些不利方面。對(duì)于C++,當(dāng)它用來(lái)構(gòu)成基于組件的圖形用戶界面編程的時(shí)候,靜態(tài)的對(duì)象模型在使用Objective C途徑的動(dòng)態(tài)消息機(jī)制方面是明顯的劣勢(shì)。對(duì)于一個(gè)高端數(shù)據(jù)庫(kù)服務(wù)器或者一個(gè)操作系統(tǒng)使用正確的圖形用戶界面前端工具的這一設(shè)計(jì)選擇不是必須的。使用元對(duì)象編譯器,我們可以把這一劣勢(shì)轉(zhuǎn)化為優(yōu)勢(shì)并且會(huì)加入當(dāng)我們遇到安全的和有效的圖形用戶界面程序編程這一挑戰(zhàn)的時(shí)候所需要的靈活性。
我們的方法比你用模板所能做到的一切更好。比如,我們有對(duì)象屬性。并且我們可以重載信號(hào)和槽,當(dāng)你在使用可以重載這一關(guān)鍵理念的語(yǔ)言進(jìn)行程序設(shè)計(jì)的時(shí)候你會(huì)感到很自然。我們的信號(hào)只對(duì)一個(gè)類實(shí)例的大小增加了零個(gè)字節(jié),也就是說(shuō)我們能在不破壞二進(jìn)制程序的兼容性的同時(shí)加入新的信號(hào)。因?yàn)槲覀儾幌衲0迥菢舆^(guò)多地依靠?jī)?nèi)嵌,我們可以使得代碼變得更小。添加一個(gè)新的連接就是增加一個(gè)簡(jiǎn)單地函數(shù)調(diào)用而不是一個(gè)復(fù)雜地模板函數(shù)。
另外一個(gè)好處就是我們可以在運(yùn)行時(shí)探測(cè)對(duì)象的信號(hào)和槽。我們可以通過(guò)使用類型安全的名稱調(diào)用而不用我們知道我們要連接的對(duì)象的確切類型來(lái)建立連接。這在一個(gè)基于模板的解決方案中是不可能的。這種運(yùn)行時(shí)的自我檢測(cè)擴(kuò)充了一種新的功能,比如我們可以使用Qt設(shè)計(jì)器的XML格式的ui文件來(lái)生成和連接圖形用戶界面。
4、調(diào)用性能不是一切
Qt的信號(hào)和槽的執(zhí)行沒(méi)有基于模板的解決方案那樣快。發(fā)射一個(gè)信號(hào)的時(shí)間大約和普通模板實(shí)現(xiàn)中的四個(gè)普通函數(shù)調(diào)用的時(shí)間差不多,Qt要求努力控制到和十個(gè)普通函數(shù)調(diào)用差不多。這也不必驚訝,因?yàn)镼t機(jī)制中包括了一個(gè)通用調(diào)度器,自我測(cè)量和基本的腳本化的能力。它不過(guò)分依賴內(nèi)嵌和代碼擴(kuò)展,并且它提供了運(yùn)行時(shí)得無(wú)比安全性。Qt的迭代(iterator)是安全的而那些基于模板的更快的系統(tǒng)確不是。甚至在你發(fā)射一個(gè)信號(hào)到多個(gè)接收器的過(guò)程中,那些接收器可以被安全地刪除而不會(huì)導(dǎo)致你的程序崩潰。沒(méi)有了這種安全,你的程序在調(diào)試自由的內(nèi)存讀或?qū)戝e(cuò)誤這種困難情況下最終會(huì)崩潰。
雖然如此,一個(gè)基于模板的解決方案不是能比使用信號(hào)和槽更加提高應(yīng)用程序的性能嗎?雖然Qt通過(guò)一個(gè)信號(hào)調(diào)用槽的時(shí)候會(huì)增加一點(diǎn)時(shí)間開(kāi)銷是真的,這個(gè)調(diào)用的開(kāi)銷只占整個(gè)槽調(diào)用的開(kāi)銷的很小比例。以上的情況都是基于Qt的信號(hào)和槽系統(tǒng)使用典型的空槽。一旦你在槽里面做任何有意義的事情時(shí),比如一些簡(jiǎn)單的字符串操作,調(diào)用的時(shí)間開(kāi)銷就可以忽略不計(jì)了。Qt的系統(tǒng)非常的優(yōu)化了,以至于任何東西都要求操作符new或者delete(比如,字符串操作或者從一個(gè)模板容器插入/刪除一些東西)的時(shí)間開(kāi)銷要比發(fā)射一個(gè)信號(hào)多的多。
另外:如果你在一個(gè)性能為關(guān)鍵的任務(wù)中的一個(gè)嚴(yán)緊的內(nèi)部回路中使用信號(hào)和槽并且你認(rèn)為這種連接是瓶頸的話,建議你使用標(biāo)準(zhǔn)的監(jiān)聽(tīng)接口模式來(lái)替代信號(hào)和槽。當(dāng)這種情況發(fā)生時(shí),總之你也許只需要一個(gè)一對(duì)一的連接。比如,你有一個(gè)對(duì)象從網(wǎng)絡(luò)上下載數(shù)據(jù),你使用信號(hào)來(lái)說(shuō)明所需要的數(shù)據(jù)已經(jīng)到達(dá)的這種設(shè)計(jì)是非常明智的。但是如果你需要向接收者一個(gè)字節(jié)一個(gè)字節(jié)地發(fā)送數(shù)據(jù),使用監(jiān)聽(tīng)接口要比信號(hào)和槽好。
5.、沒(méi)有限制
因?yàn)槲覀冇性獙?duì)象編譯器來(lái)處理信號(hào)和槽,我們可以向它添加一些其它模板不能做的但很有用的東西。在這之中,有我們利用生成的tr()函數(shù)進(jìn)行作用域翻譯,和一個(gè)自我測(cè)量和擴(kuò)展的運(yùn)行時(shí)的類型信息的先進(jìn)的屬性系統(tǒng)。屬性系統(tǒng)有一個(gè)獨(dú)一無(wú)二的優(yōu)勢(shì):沒(méi)有一個(gè)強(qiáng)大的和自我測(cè)量的屬性系統(tǒng)——如果這不是不可能的 ——一個(gè)Qt設(shè)計(jì)器這樣的強(qiáng)大的和通用的用戶界面設(shè)計(jì)工具就很難被寫(xiě)出來(lái)。
帶有元對(duì)象編譯器預(yù)處理器的C++從本質(zhì)上給我們帶來(lái)對(duì)象的C的靈活性或一個(gè)Java的運(yùn)行時(shí)環(huán)境,當(dāng)保持C++的唯一特性和可伸縮的優(yōu)點(diǎn)。它使得Qt 成為我們今天擁有的靈活和舒適的工具。
小結(jié):如何Qt 用模板來(lái)實(shí)現(xiàn)信號(hào)和槽的內(nèi)容介紹完了,希望本文對(duì)你有所幫助,關(guān)于信號(hào)與槽更多的資料請(qǐng)參考編輯推薦。