Qt和MFC的比較
在當今基於C++的圖形界面開發領域,能與Qt相抗衡的也只有MFC,MFC是微軟公司的基礎類庫,自然得天獨厚,比如開發深層次的Windows應用,MFC當然遠超Qt,但Qt也有殺手鐧,那就是跨平臺。這兩點大家一目了然。下面我們再來比較它們的其他特點。
(1)開發速度
就整體而言,MFC可能會快捷一些,因為Windows平臺的開發工具大多很智能,因為立足於Windows的開發人群很廣,從菜鳥到專業人士(開發人員一多,技術參考就多,周圍可以諮詢問題的人就多)。相比較而言,Qt基於Linux,可用的開發工具不多,而且這些工具大都比較專業,多是第三方的產品,加上這些工具的集成度不高,支持的第三方庫也沒有支持MFC的第三方庫多,因而從這一點看,MFC略勝一籌。不過,Qt自從被諾基亞公司收購後,官方發布了跨平臺集成開發環境Qt Creator,之後的走向就不好說了,作者個人的總體感覺是Qt Creator和VS差距比較大,還需要改進。
從庫本身來說,Qt集成的功能比MFC龐大,而且使用的封裝技術(信號/槽)倍受讚許,比如Qt Script為Qt提供了嵌入式腳本,Qt界面庫支持CSS,所以Qt構建出來的界面比MFC要好,且實現過程也比較容易。為了降低使用Windows SDK開發的難度以及提高使用Windows SDK開發的效率,MFC採用的是淺層封裝(最新的2008 sp1加入了BCG的高級界面庫,可能有所改善)Windows SDK。這個方面相比而言,Qt庫比MFC優秀。不過,這兩個庫都久經時間的考驗,穩定性都很高,幾乎沒有什麼Bug。
(2)運行效率
MFC採用淺層封裝,運行效率比較高,加上VC對Windows進行了針對性的優化,因而整體性能是比較高的,但是如果加入第三方庫就不敢保證整體的高性能了。Qt庫比較龐大,封裝層次較深,所以運行效率比MFC低,但是在如今主流計算機系統的配置下,人們還會介意這點性能差別嗎?(反正大家都不介意C#對性能略微拉低的影響了。)
(3)應用範圍
如今Windows的普及率無人能及,MFC的使用人數自然就多,相比而言,Qt主要是Linux下的開發人員在使用。MFC不支持嵌入式開發(主要是指手機平臺),而Qt有對應的支持模塊,雖然這一手機開發領域被Java碾壓,但總歸還是有Qt的使用空間。
(4)學習難度
Qt的封裝方式比較明晰,和系統隔離得比較好,作者個人覺得學習的門檻不高。而MFC則較難精通,因為深入開發之後還需要了解SDK,否則開發出的程序比較初級。
(5)偽對象vs真對象
歸根結底,Qt和MFC的差異在於其設計的差異。MFC的根本目的是讓開發者調用封裝好的、用C語言編寫的Windows API。但是,這絕非好的面向對象的程序設計模式,因為在很多場合,我們必須提供一個包含15個結構成員的C語言的struct(結構類型),但是其中只有一個結構成員是我們需要使用的,或者必須用在調用函數中使用參數的方式來獲得我們需要的結構成員。MFC還有許多讓人摸不著頭腦的地方,例如函數名沒有任何連續性,假如我們創建了一個graphical類,直到調用了creat()以後該類才會被創建。然而對於dialogs類,必須要等到調用OnInitDialog()才能創建這個類的實例對象。奇怪的是到了views,創建該類的函數名竟然成了OnInitUpdate(),使用VC/MFC中的庫函數調用總是要十分小心,不如Qt那樣一看函數名就知道對應函數的作用是什麼。
(6)消息循環
MFC是事件驅動的架構。必須對任何操作對應的特定消息做出響應。Windows中應用程式發送的信息數以千計,遺憾的是,要釐清這些紛繁蕪雜的消息很困難,通過參考這方面的文檔資料並不能很好地解決這些問題。
Qt的消息機制建立在SIGNAL()發送和SLOT()接收的基礎上。這個機制是對象間建立聯繫的核心機制。利用SIGNAL()可以傳遞任何參數,它的功能非常強大,可以直接傳遞信號給SLOT(),因此可以清楚地理解要發生的事情。一個類所發送的信號數量通常非常少(4個或者5個),相關的幫助文檔資料也非常齊全。這讓我們會覺得到一切盡在掌握之中。信號/槽(Signal/Slot)機制類似於Java中的listener機制,不過這種機制更加輕量級,功能更齊全。
(7)創建界面
MFC無法創建大小動態可變的子窗口 ,必須重新手動修改代碼來改變窗口的位置(這恰好解釋了為什麼Windows裡的對話框dialog是不可以改變的),這個問題在軟體進行多語言化版本設計時更加嚴重,因為許多國家或地區在表達相同意思時可能需要更長的詞彙和句子,於是軟體開發者必須對每種語言的版本重新修改自己的軟體。
在Qt中,界面需要的任何設計都可以手動編寫出來,因為它很簡單:為了得到一個按鈕(button),可以將代碼寫為「button = new PushButton( "buttonName", MyParentName );」,如果想在按下某個按鈕以後調用某段執行代碼,則可以編寫為「connect(button, SIGNAL(clicked()), qApp, SLOT(action()));」。Qt擁有非常簡單而又不失強大的設計機制,不使用它實在可惜。
Qt還提供了一個圖形用戶工具——Qt Designer,可以用來協助建立用戶界面。可以使用Qt Designer修改所使用的任何控制項的屬性,不用將這些控制項拖放到設計嚴格限定的位置,因為可以通過設計機制更完美地組織這些控制項。
Qt Designer這個工具所生成的代碼可閱讀、可理解。所生成的代碼單獨放在一個文件中,在編程的同時,我們可以隨心所欲地多次重新生成用戶界面。
Qt Designer可以讓我們完成許多在MFC中不可能完成的任務,比如用預先填好的內容生成列表視圖(listview),在每個頁籤(tab)上使用不同的視圖(view)。
(8)幫助文檔
用戶選擇圖形開發環境的時候,幫助文檔是否周全是左右用戶選擇圖形開發環境的重要因素。Visual開發環境的幫助文檔MSDN(這個還要單獨掏錢購買)非常龐大,有10個CD-ROM光碟容量之大,它包羅萬象,涵蓋廣泛,但難免有泥沙俱下、主題模糊、關鍵信息不突出的遺憾。MSDN的連結設計也很糟糕,通過連結很難從一個類跳轉到它的父類或者子類以及相關的類。如果搜索一個關鍵字,結果找到的內容不管是否直接關聯,只要包含這個關鍵字的信息統統都會搜索出來,讓用戶再從中選擇。
Qt的文檔設計得相當優秀,可以到https://doc.qt.io/上面一睹它的芳容。Qt的文檔完備且詳細地覆蓋了Qt的方方面面,然而文檔的整體容量竟然僅有18MB。其中每一個類和方法都被詳盡描述,巨細靡遺,舉例充實。通過Trolltech公司提供的連結或者是Qt Assistant工具可以方便地從一個類或者方法跳轉到其他的類。文檔還包含了一個初學者教程和一些典型應用的例子。同時還提供了FAQ和郵件列表,方便用戶通過用戶群或通過Internet來查閱。如果我們購買了授權,在一天之內就會得到Trolltech公司的技術支持。實際上,Qt優秀的幫助文檔使得尋求外部幫助的機會大大減少。Trolltech公司的宗旨之一是:有如此優秀的Qt產品及其幫助文檔,其他外部的技術支持就是多餘的。
總之,MSDN用熟了也很好用、很全面,相關的背景知識、例子都能找到,而且網上還有豐富的範例程序可以參考。同樣的,僅憑Qt的幫助文檔也絕對不足以解決所有問題,以作者的親歷,在網上只找到了一個Qt中文論壇,提過幾個問題,有的問題給出了解決辦法,有的問題則沒人回答,最後還要靠自己試。
(9)Unicode編碼
使用MFC,如果要顯示Unicode編碼的字符,在編譯連結時必須用到特殊的參數(還要改變可執行文件執行的入口),必須在每個string前面加上T,將char修改成TCHAR,每個字符串處理函數(strcpy()、strdup()、strcat()等等)都要改變成另外的字符串處理函數名。更令人惱火的是,支持Unicode的軟體竟然不能和不支持Unicode編碼的DLL一起工作。這是一個很嚴重的問題,但是我們卻別無選擇。
使用Qt,字符串用QString類來處理,QString類與生俱來就採用Unicode編碼,因而不需要改變任何東西:不需要在編譯/連結時增添參數,不需要修改代碼,只需要使用QString類即可。QString類功能強大、應用廣泛,也不用擔心Unicode問題。QString類提供了轉換為char * 和UTF8的函數。MFC的CString類設計相比於Qt的QString類設計則有著巨大的不同,CString類以char *為基礎提供的功能很少,它的特點是當需要char *類型時,可以直接使用CString類。乍看起來這好像是個優點,實質上有很大缺陷,特別是可以直接修改char *內容而不用更新類,在轉變為Unicode時就會遭遇到很大的麻煩(CString類隨編譯選項可以是Unicode版)。相反,QString類在內部以Unicode編碼方式來存儲字符串,需要時提供char *功能,實際上很少用到char *,因為整個Qt的API用文本的方式響應QString參數。QString還附帶了許多其他的功能,比如自動分享QString的內容。總之QString是一個非常強大的類,需要用到它的地方很多。
(10)支持軟體的多語種功能
MFC可以支持軟體的多語種功能,需要將每一個語種的字符串放在一個字符串表中,在代碼中需要之處調用LoadString(IDENTIFIET),然後把這些字符串資源轉化到DLL中,這些字符串對應到所需要的語言,改變圖形界面,再通過程序調用這個DLL。整個過程是如此的煩瑣,可謂牽一髮而動全身。
Qt支持軟體多語種的方式有所不同,只需要將字符串置於函數tr()中,可以直接在代碼中改變字符串的引用。Qt Linguist(Qt的一個工具)能夠提取所有待翻譯的字符串並按照對應語種的用戶界面顯示出來,這個工具非常適合進行用戶界面的多語種翻譯,它功能齊全:通過查詢字典數據顯示出對應語種的字符串內容,正確顯示出Unicode編碼,以快捷方式檢測出未翻譯的字符串,檢測字符串修改的情況。這個工具甚至可以提供給沒有任何編程經驗的翻譯人員用於翻譯軟體的用戶界面。該軟體的發布遵循GPL版權規則,開發者可以根據具體的開發需求來修改它。翻譯之後的文檔保存在XML中,符合軟體復用的原則。由此可見,為軟體增加一種新的語言版本僅僅是用Qt Linguist工具生成一個新的文件而已。
(11)資源問題
使用MFC時,一部分開發過程要依靠「資源」(resources),在很多的案例中開發者都必須使用它們。這樣會導致如下後果:除了Visual Studio,很難使用其他的工具來完成開發。資源編輯器僅有有限的功能,比如通過Dialog編輯器不能改變所有的屬性。
然而,Qt並沒有資源的概念,這就解決了MFC所遇到的問題。Qt提供了一個界面設計器以可視化的方式來設計界面,並把設計後生成的代碼存儲到一個腳本文件中。
(12)價格
用戶一旦購買了Visual Studio,將免費獲得MFC SDK。Qt在UNIX上可以免費獲得遵守GPL版權規則的版本(現在可以免費獲得Windows平臺上的GPL版本)。如果要開發不公開原始碼的軟體,則必須購買Qt的授權。在特定平臺下,每個開發者購買一個永久性授權,並可獲得一年的技術支持。
(13)發布
在發布基於MFC的軟體時,必須依靠存儲在客戶計算機上的MFC,但是這是不安全的,同樣是MFC42.dll,基於相同的庫可得到3個不同的版本。因而需要檢查是否擁有正確的MFC42.dll版本,如果版本不對,就升級它。但是,升級MFC42.dll會改變很多軟體的行為。這讓開發者感到很不「爽」,如果用戶在安裝軟體以後導致用戶的計算機死機了,該怎麼辦呢?
Qt則沒有這個風險,因為Qt壓根就沒有「升級整個系統」的概念。不過,如果開發的軟體不是基於同一個版本的Qt來運行,還是會有潛在的問題。