应用框架: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++确必须要弹出一个模式对话框。
>> 本文固定链接: http://www.vcgood.com/archives/1008