應用框架:mfc?有kfc流行嗎?
應用程序框架(application frame),有時也稱為對象框架。visual c++采用的框架是mfc。mfc不僅僅是人們通常理解的一個類庫。(同樣,delphi的vcl也不僅僅是一個控件庫,盡管它的名字叫“可視控件庫”。)你如果選擇了mfc,也就選擇了一種程序結構,一種編程風格。mfc早在windows 3.x的時代就出現了,那時的visual c++還是16位的。經過這些年的不斷補充和完善,mfc已經十分成熟。但由於原型出現得比較早,mfc相比於vcl落後了一個時代。盡管微軟對mfc的更新沒有停止,我也經常讀到“只要windows不過時,mfc就不會過時”之類觀點的文章,但就象inprise(原borland)的owl框架的淡出一樣,mfc的淡出也是早晚的事。其實mfc是和owl同一個時代的產物。owl已經不在了,mfc怎能不“居安思危”呢?如果mfc青春永駐,微軟的開發人員也不會“私自”開發出基於atl的wtl呀。當然,wtl的地位不能和mfc比,它並不是微軟官方支持的框架,封裝的功能也相當有限。但至少也反襯出了mfc存在的不足。
我以為,最能體現一個應用程序框架的先進性的是它的委托模型,即對windows消息的封裝機制。對windows api的封裝就不用說了吧。大同小異,也沒什麼技術含量。如果高興,你也可以自己寫一個類庫來封裝。但對windows消息驅動機制的封裝就不是那麼容易的了。最自然的封裝方式是采用虛成員函數。如果要響應某個消息就重載相應的虛函數。但出乎我的意料,mfc采用的是“古老”的宏定義方法。用宏定義方法的好處是省去了虛函數vtable的系統開銷。(由於windows的消息種類很多,開銷不算太小。)不過帶來的缺點就是映射不太直觀。對於mfc,則是“太不直觀”了。它的消息映射代碼雖然是可見的,但“勸君莫碰”。好在vc的classwizard可以自動生成消息映射代碼,使用起來還算方便。但和vcl的委托模型相比,mfc的映射方法就顯得太落後了。而delphi的object pascal因為沒有“標准負擔”,語言引入了組件、事件處理、屬性等新特性。由於功夫做在編譯器級,生成的源代碼就顯得十分簡潔。似乎vc是“讓框架遷就語言”,而delphi是“讓語言遷就框架”。
我想舉一個對字符串操作的封裝的例子來說明mfc和vcl的優缺點。在mfc中,cstringlist類有加入、獲取、刪除等功能,但vcl的tstringlist類除了上述功能還有排序、從逗號分隔的字串讀入、流輸入輸出等功能。但同樣的字符串替換功能,vcl的stringreplace要比mfc的cstring::replace慢2~3倍。總的來說,vcl的封裝比mfc更為高層,更為抽象,但不可避免地帶來的問題是某些部分執行效率比mfc略低。這就象低級語言(如匯編)的執行效率比高級語言(如basic)高,但編程效率較低。魚和熊掌不可兼得嘛。
vcl比之mfc的另一優點是對異常處理的支持,而一大缺點是對多線程支持差。vcl的大部分都不是針對多線程優化的。雖說vcl提供了簡化多線程操作的類,但只是工作者線程(worker threads)使用起來比較簡單。如果線程要和界面打交道的話事情就變得麻煩了,因為除了應用程序的主線程,任何線程不能訪問任何可視的vcl部件。你不得不使用synchronize方法等待主線程處理它的消息,然後在主線程中訪問vcl部件。而mfc就沒有這樣的限制。
穩定性與完善程度:vc是老大哥
vc要比delphi穩定和完善。vc的發展歷史比delphi長,微軟的總體實力比inprise強。vc的框架mfc經歷了那麼多年的發展和完善,功能非常全面,而且十分穩定,bug很少。其中你可能遇到的bug更少。而且有第三方的專門工具幫助你避開這些bug。如此規模的一個類庫,能做到這一點不容易。不要小看了這一點,很多專業程序員就是為這個選擇vc的。因為盡管vcl比mfc的抽象程度高,封裝較為高層,但由此帶來的開發效率的提高對高手來說畢竟是有限的。而如果你遇到一個怪問題,調試了半天,發現不是你的代碼有錯,而是vcl的bug,你作何感想?雖說遇到這類問題的可能性很小,但對vcl的形象的影響可不小。delphi的ide太占資源,啟動速度太慢,和某些顯卡驅動程序沖突,vcl中有bug,調試器不夠健壯,對不穩定的第三方控件沒有防護措施……問題多多,在這方面delphi不如vc。希望inprise能更上一層樓。順便說一下,我在網上看到有些人極言delphi的不穩定,說幾分鐘出現20多次非法操作。delphi的確不如visual c++穩定,但也不至於如此呀。我估計是那位朋友的delphi裝了某些有問題的第三方控件,導致了delphi的頻頻出錯。不妨卸下那些控件試試?
可移植性:立足現實,放眼未來
inprise正在開發delphi的linux版本,代號為kylix。也許通過kylix,用vcl構架編寫的windows程序向linux移植成為可能。但這只是可能。因為在目前inprise的兼容性工作做得並不好。低版本的delphi不能使用高版本的vcl組件(這還別去說它),而高版本的delphi竟然不能使用低版本的vcl組件。真是豈有此理,我很少看見軟件有不向下二進制兼容的。如果windows 98不能運行95的程序,windows 95不能運行3.x的程序,win 3.x不能運行dos程序,你還會用windows嗎?如果windows 95的程序必須經過重新編譯才能在98下運行,98會賣得那麼好嗎?“同門兄弟”c++builder和delphi也不能互相使用對方的組件,甚至同一套vcl庫的文件名也不一樣。所以一個組件有for d1/d2/d3/d4/d5/c1/c3/c4/c5這些不同版本是常有的事,而且隨著delphi和c++builder版本的升級可能還會增加。希望inprise能先解決同門兄弟的兼容性問題。而微軟的vc就沒有這類問題。mfc1.0的程序也可以毫無障礙地在vc6.0下編譯通過。
集成界面:宏觀與微觀
就大處說,vc的集成界面是不如delphi的。delphi僅僅一個object inspector就可以將vc的一堆wizards比下去,何況它還有code explorer、todo list等。但從小處,又可以看出delphi的不成熟。比如“自動完成”功能的智能化程度和提示詳細程度不如vc,響應速度也沒有vc快。
visual c++所帶的msdn是一部“開發者的百科全書”,信息龐大,查詢方便,這方面比delphi更加專業。很多幫助項都有源程序示范。
delphi的opentools是完全面向第三方的開放系統,開發者可以修改很多borland公司自身的功能,從ide的可擴充性上說delphi更好。
調試:細微之處見真功
visual c++和delphi的調試功能都非常強大,同時都具有單步可視化調試、斷點跟蹤、運行時改變變量、鼠標指向可以得到變量值等等功能。對dll的輸入輸出也能方便的管理,能夠進行源碼級別的調試。
相對而言,visual c++能夠更加方便地看到變量的變化情況,這包括對結構可以展開成數據樹,從而了解每一個變量的值,每一步調試,變化了的變量會加紅,從而使調試更加方便。另外,visual c++的塊內存察看比delphi也要方便。
當然,delphi也有很多體貼的細微之處,比如在線程調試的時候,delphi能夠很方便地察看線程的變化,visual c++確必須要彈出一個模式對話框。