MFC?VCL?

最近网上争论VC和DELPHI/BCB优劣的朋友甚多(其实不是最近,一直都很多),其实真正有分歧的多半在MFC和VCL两套类库的选择上。不知道诸位对这两套类库,或者说是Application Framework(下面简称AF)的理解究竟如何?

对于一套AF,跟一套类库class library最大的不同,在于它是一套完整的已经构建好的框架,风格、结构都已经做好,你不得不去遵守,而类库讲究的是拿来主义,理想的境界应该是可装配的元件(Component),比如标准模板库STL就是一个最后的例证。AF大抵都有几大要素,侯sir的大作《深入浅出MFC》中详细讨论了MFC的六大关键技术,其中比较重要的是:运行期类型识别(RTTI)、动态生成(Dynamic Creation)、永久生存/序列化(Perisitance/Serialization)和消息映射(Message Mapping),还有一个候sir没讨论的线程安全(Thread Safety)。关于这些问题,我和myan大哥曾经在E-MAIL略有讨论,下面分别谈点我的想法。

首先,现在流行的AF基本上都是采用的单继承,原因嘛,让我猜的话,从技术上讲,CObject/TObject/java.lang.Object可以通过RTTI或者相关信息,可以唯一确定父类,如果void*和多继承显然就不行,当然也许跟多继承的麻烦和菱形结构的尴尬有关系(详细的可以看看Thinking in C++里对多继承MI的论述);从商业角度想,谁都不愿意用户再去用别人的AF,趁此机会做个限制。当然单继承带来的就是一根非常非常huge的继承树,所以Java现在是越来越难学,正如同JDK是越来越臃肿庞大。

RTTI是比较新的语言提供的能力,比如C++新标准,Object Pascal(DELPHI)和Java,主要是Dyanmic cast需要进行类型检查,以及抛出异常(exception,也有人喜欢叫“例外”)的时候需要输出一些跟类相关的诊断信息。其中C++的RTTI最为简单,只能获得类名和相关的继承信息;而Object Pascal和Java都更为复杂,甚至于可以或者属性名和方法名。作为C++形式的AF,标准C++提供的信息显然不够,于是MFC自成一家搞了一套自己的RTTI,然后成为各位Anti-MFC斗士口诛笔伐的对象。
顺便我帮微软辩护一下,其实仔细想想就应该明白Microsoft的无奈:C++标准只规定了typeid可以获得类名及相关信息,但对输出的格式、二进制的组织格式没有任何的规定,而typeid并不完全是编译器内部实现,还依赖于头文件<typeinfo>里定义的结构,于是天下大乱。比如一个class A,在Borland的编译器上获得的类名是“A” ,在Microsoft/Intel编译器上是“class A”,在gcc上是“1A”(如果是个模板类,gcc上甚至可能是乱码),且储存typeinfo的结构居然还不一样。而MFC是被Microsoft、Borland、Synamtec、Watcom等等诸多编译器使用并动态连接到MFCxx.dll,如果用标准C++的RTTI和exception,不当机才怪。所以您见过多少使用标准C++作为RTTI的AF?比较流行的比如Qt(KDE)和codeguru上可以看到的VCF(Visual Component Framework,C++写的),都是自成体系的RTTI。而Object Pascal(DELPHI)和Java都分别只由一家公司开发,当然不存在C++的问题。
    由于现在的AF基本上都是采用的单继承,所以可以获得父类的名称。MFC提供的RTTI其实跟标准C++差不多,主要也是获得类名和一个IsKindOf(标准C++里可以用dynamic_cast检验),而VCL和JDK的RTTI都可以获得所有的interface和所有的method的信息,这也是Sun抨击C++的论据之一。其实想来好笑,首先RTTI是所有特性中最简单,无非就是记录下一些信息而已,自己记不就完了?比如MFC就是用宏(macro,您不会喜欢叫它“巨集”吧?)的方式记录自己的RTTI,而codeguru上那个VCF更进一步,用宏记录下所有method和property的信息,这下就跟VCL/JDK一样了。而Qt(KDE)更干脆,直接用MOC帮你写。其次,RTTI过多导致臃肿,并且知道所有的method名字有用吗?无非是用于IDE了,对使用者可是没多少好处。

动态生成和永久生存/序列化标准C++并没有提供,据说曾经要在STL搞一个,后来也没了下文。当然MFC也用宏是模拟的,不过serialize就要麻烦诸位自己动手写了。VCL是通过TStream类中的ReadComponent和WriteComponent实现,而且挺自动的,不用象MFC一样自己写。原因何在?VCL不是有属性(Property)吗?其实就是把所有的property的内容写了进去。如果把property看成一个smart pointer的话,其实smart pointer初始化的时候就可以注册,然后就能提供RTTI和自动的serialization了。从这里看,VCL的确要简单一些,当然C++写个smart pointer也可以做到。

消息映射其实并不用说太多,宏的直接映射和VCL的委托模型其实原理上差得并不远。VCL的方式很直接,略有效率损失,MFC方式的详细讨论多看看侯sir的书就行了。我想多说一点的是Qt(KDE)所用的signal-slot模型,很有意思,直接connect就OK,不过很遗憾,这是建立在对C++的扩充(说难听点叫对C++标准的肆意践踏)上的,需要用它的MOC预处理一下。

线程安全的问题是老大难了。C从UNIX脱胎到C++成型的时候,UNIX上还是以进程为概念,并没有线程的影子。只是到了GUI时代,后台处理跟前台响应(比如对鼠标动作的处理)争CPU的问题日益严重,现在几乎所有OS都有了线程的概念,可惜标准太多,比如POSIX和WINDOWS的线程模型就差得太远,导致写的程序跟平台相关性很大,C++标准里并没有对此作出什么回应。MFC里的线程模型就是WIN32的实现,主要是关键代码段(Critical Section)和一些内核对象(Event、Semaphore等等),VCL也主要实现了Critical Section和信号灯(Event)。在同步方面,由于MFC的半封装(MFC经常被骂的跟API关系太大)倒把这个责任扔给了API,问题不大;而VCL就惨了,其他线程根本不能干扰主线程的工作,只能申请,然后其实是以单线程的方式在工作,有时候真的不如不用。Java吹嘘的线程就不用多提了,借myan的e-mail里一句话,“Andrei和Dinkumware的Pete Becker说,Java的多线程是给不会编程的人用的,toy-like。”

总结性说一下。
    MFC整个结构的实现主要是靠宏,一堆一堆令人头痛的、无法让编译器进行类型检查的宏。当然我相信微软的初衷是只让您用而不是让您去搞懂这些宏。VCL的实现主要是来自Borland对Object Pascal的扩充,比如__closure扩充了C++的类成员函数指针,__published增加的__property以及RTTI方面增加的__classid。看起来呢,MFC就显得拖沓繁复,但是兼容性很不错(要不怎么可以在这么多编译器上用呢?);而VCL的看起来挺简洁,不过这种肆意的扩充带来的恶果便是没有portability,所以VCL不会象MFC那样广泛的用在各种编译器上。
    在思想方面,MFC主要是Document/View的架构,限制性太强,这就不如VCL的Component随意组合来得漂亮。但是需要提一点,许多人认为VCL封装的层次高,比MFC更抽象,因此更好,最直接的例子就是VCL的TCanvas类和MFC的CDC类的对比。而我的看法是,虽然是AF,但是最后类与类之间的关系应该做到既能协同合作,耦合性、依赖性又要尽可能的小,这样才是真正的Component,可以随意组合的积木式Component。VCL里的Component组合只是针对VCL里的类而言,跟外界没什么联系,并且类之间的依赖关系太大,而MFC半封装的特性却使MFC在这方面做得很好。

最后不得不说一句,我很讨厌AF,因为我讨厌那棵庞大的继承树,我讨厌那种抑制自由的框架结构。STL在这方面就做得非常好,而Microsoft和Borland也在前进,分别又有了另外一套类库,ATL和CLX。当然ATL还是秉承Microsoft不跨平台的一贯宗旨,但是写得实在是非常漂亮,彻底扔了MFC,充分运用了C++独有的模板和多继承技术,轻量。恕小弟实在才疏学浅,不敢乱加评价,诸位有兴趣多看看潘大侠的大作;而CLX从Borland提供的一些文档看来,结构跟VCL似乎没什么大的区别,还是老套的深继承树,当然这跟Borland非要把Object Pascal作为它的产品中轴有关系,而Object Pascal没有C++那些独特的能力。

一家之言,希望大家发表自己的看法。

原文:http://www.newasp.net/tech/program/20108.html

时间: 2024-08-04 12:38:55

MFC?VCL?的相关文章

c编程实例:809*??=800*??+9*???+1

程序代码: #include<stdio.h>#include<stdio.h>void main(){ int c; int i,j,k; printf("start computing!!!"); for(i=10;i<100;i++){ for(j=100;j<1000;j++){ c=i*809-1-9*j; k=c%800; if(k==0){ k=c/800; if(k>10&&k<100) printf(&q

什么是带宽?宽带独享?共享?

所谓带宽(bandwidth)可以通俗理解为单位时间内访问网络的的最大数据流量.如果使用100M网络交换机,局域网带宽可以达到100M:如使用10M交换机则只能达到10M. 主要是访问互联网的速度,这个可以和电信部门推出的"宽带"和"窄带"用户一起综合理解,所谓"窄带"用户,一般指拨号上网用户,通过MODEM拨号上网速度一般不会超过64K,带宽很窄:而"宽带"用户指ADSL或社区宽带网用户,上网速度可以达到512K-100M(

C#中 ? 和?? 的用法

C#中 ?? 和? 的意思 1.? 如果直接定义一个 值类型,给负值null:就会提示“无法将 Null转换成‘值类型(比如:int)’,因为他是一种不可为null的值 de类型” 例如 int in=null;//错误 int? in=null;//正确 string result=null;//正确 因为string是引用类型不是值类 型 string? result=null;//错误,因为?,只能用于值类型 2.?? var name??:“Hello World!”;//如果name为

所有的视图是否都可以更新?为什么?

(1)若视图的字段是来自字段表达式或常数,则不允许对此视图执行INSERT.UPDATE操作,允许执行DELETE操作:      (2)若视图的字段是来自库函数,则此视图不允许更新:      (3)若视图的定义中有GROUP BY子句或聚集函数时,则此视图不允许更新:      (4)若视图的定义中有DISTINCT任选项,则此视图不允许更新:      (5)若视图的定义中有嵌套查询,并且嵌套查询的FROM子句中涉及的表也是导出该视图的基表,则此视图不允许更新:      (6)若视图是由

近视?老花眼?恢复视力,就用这一招!

近视?老花眼?恢复视力,就用这一招! 2016-04-18 小编说: 如果家里有小孩近视.老人眼花.玩手机后眼睛疲劳的,都可以用这个方法,不伤眼,帮助恢复视力! 平时习惯 蒸熏眼睛 首先平时习惯是:勤眨眼和用蒸汽熏眼睛:倒杯热水,在温度不烫人时,将眼睛放到杯口熏蒸几分钟. 明目操 另外除了上面的两个习惯以外,还需一套明目操.该操步骤如下: ▲ 看笔尖缓解近视. 1.找把椅子坐下,眼睛正视前方.拿一支铅笔放在面前,眼珠盯着笔尖看,然后慢慢地把笔移近双眼,直到触碰鼻子:继续盯住笔尖,慢慢地把笔移回原

Java培训哪里好?怎么样?

Java培训哪里好?怎么样?据兄弟连Java培训数据统计,最近这两年参加Java培训的人越来越多,Java为什么会这么火呢?它的功能到底有多强大呢,接下来就我自己对Java的了解和大家分享一下. 首先,参加Java培训可以零基础.Java是一门容易入门的技术,即使你没有任何的基础经过一周的培训也能学会其中的门道,所以Java的门槛相对比较低,即使不是计算机专业的学习起来也完全无压力.身边有学设计的朋友在大学毕业时选择了在兄弟连参加Java培训,经过四个多月的强化学习,现在也有一个很不错的Java

出国?上研?工作?回家种田?(一) 出国看世界

本科生毕业主要有四个选择:出国,上研,工作,还有回家种田,不对,其实我是想说创业-- 我自己只是本科毕业找工作了.原先也是在这个问题上面做了很多研究,问过不少人,周围也有不少同学上研.出国之类,这里把我知道的东西给总结一下.其中有些内容也是道听途说,或是自己的理解和猜想,尤其是关于上研情况的看法,作为本科生,其实我没有太多发言权,但是尽量按我所知道和所理解的写一写吧.也希望知道更多情况的人来补充.每个人都有自己的选择,每个选择都有其好处和坏处,没有绝对正确的答案. 出国看世界 出国途径其实很多,

深度学习框架哪家强:TensorFlow?Caffe?MXNet?Keras?PyTorch?

深度学习框架哪家强:TensorFlow?Caffe?MXNet?Keras?PyTorch?对于这几大框架在运行各项深度任务时的性能差异如何,各位读者不免会有所好奇. 微软数据科学家Ilia Karmanov最新测试的结果显示,亚马逊MXNet在CNN.RNN与NLP情感分析任务上性能强劲,而TensorFlow仅擅长于特征提取. 测试详情更新在Ilia Karmanov的GitHub项目DeepLearningFrameworks(https://github.com/ilkarman/De

日常2018/4/9---b/s和c/s架构分别是什么?区别?

b/s和c/s架构分别是什么?区别? b/s是指前后端分别是 Browser/Server的模式. c/s是指前后端分别是 Client/Server的模式. 参考:https://blog.csdn.net/tennysonsky/article/details/45062079 https://baike.baidu.com/item/Client%2FServer?fromtitle=C%2FS&fromid=826311 上班去了晚上补充 原文地址:https://www.cnblogs