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