最后,Visual C++的编译和连接时的错误信息比 Delphi 要详细和具体的多。特别是使用
ATL 开发更加如此。
应用框架:
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 就
没有这样的限制。