huaxiazhihuo

 

MFC,一开始就错了

        谨以此文祭奠过去多少年下来,日日夜夜学习MFC源代码的宝贵时光。

        曾经以为MFC是世界上最神圣无比的东西,发誓在没彻底弄透MFC之前,绝不越雷池半步,碰都不要去碰LISP、ERLANG、PYTHON、VCL、ATL、STL、LOKI、BOOST各种美妙的好东西。即使一再听到高人说MFC设计得不好,非常糟糕,也都至死而不悔,然后只要稍微听到有人在说MFC的伟大,心里就特别高兴。买了各种各样的VC方面的书,什么四大天王、什么几十百千例、什么VC项目实例,彻夜苦读,单步调试,一次又一次地徘徊在MFC套来套去的各种美妙代码之中,观察里面各个对象的值。一次又一次地感叹MFC的伟大,一直在想,这辈子,如果能彻底地掌握MFC里面的一切秘密,朕就心满意足了。终于有一天,终于彻底醒悟,原来MFC真不是好东西,不过就是那些伎俩而已,真不该将它看得如此的伟大。这种念头一起来,再回过头来看MFC的一坨一坨代码,只觉得清晰无比,又感觉代码之中充满了各种无奈。接着再看看那些VC方面的书,除了四大天王还稍微有些可取之处,其他的任何一本,奇臭无比,没有一行代码经得起推敲, 文笔也糟糕无比,其内容又一再重复,抄来抄去,真正是一本又一本的狗屎。 感叹一下:这些书牺牲了多少宝贵的树木,又折磨死了多少读者的脑细胞,实在罪大恶极。

        在MFC大河日下的当今的大环境之下,在下也不想对它落井添石,毕竟也在其上学到不少好东西,特别是阅读代码的能力,试问这么糟糕复杂的框架都可以精通,天下还有什么代码能看不懂(别自信满满,你敢碰BOOST里面的那些奇技淫巧,匪夷所思的幻码吗)。但实在忍受不了躯体内另一个人日日夜夜,旦夕不停的诉求,兼之又一直恨铁不成钢,又为自己失去的青春阵痛不已。而VC2008中BCG的出现之后,VC2010还依然保留着那些蠢笨无比的BCG文件,不思悔改,终于让某彻底对MFC死心了,这货没得救了。

        好吧,废话少说,赶紧进入正题。

        国内C++界中一大侠说过,任何东西,都要先抓住其主干,其他的一切细节,都可以留待以后慢慢补充,否则,一开始就陷入细节,想跳出来就不容易了。大侠此语,实在有道理。(不知为什么,此大侠后期一直在对C++表示不满,当然,人家现在的境界,岂是我等小民所能体会)。不说其他,就说在C++中,必须站在一个高度上,纵观全局,才能将一切看得通通透透。于是,下面就尝试爬上高峰,来俯瞰MFC中的众生。MFC的主干,在下看来,既不是什么六大关键技术,也不是什么文档视图结构,更不是COM的封装,而是为了将原始的API中的各种对象,好比窗口、GDI、设备环境等,都映射成相应的多线程安全的C++对象,好比将HWND搞成CWnd,以期减轻WINDOWS下界面开发的工作量。

        这种想法,其实也无可厚非,如果真能封装得好,确实可以提高生产代码效率,但是从C++和WINDOWS的设计观念中来看,这种映射,还是存在很大的问题,稍后再述。问题在于,MFC的实现,异常丑陋呆板,通过几个全局的线程安全局部变量的映射表,将句柄(Handle,此词译得相当令人恶心)与其相应的C++对象指针形成一一对应,并且指定,在大部分的消息处理和参数传递中,所有的参数由原本的句柄一律由对象指针来代替,然后就高高兴兴地宣称已经完成任务了,这实在让人哭笑不得。不说别的,即使是消息处理,MFC即使已经做了很大的努力,也都无法将句柄参数搞成对应的对象指针,单是这一点,就已经失败了。然后再看看,它最后封装的做法,不过是将API函数中的第一个参数为句柄的都改成相应的C++对象的函数成员,好比将SetWindowText搞成CWnd::SetWindowText,美其名曰,薄薄的封装。这真是要笑掉大牙了,既然是这样的薄薄的封装,那还干脆不如不封装了,我想破了头,也看不出这样的封装,带来了什么样的好处。反而将原本全局函数的各种灵活性,都给葬送在类成员函数这个监狱中。全局函数的各种好处,除了是全局这个缺陷之外,实在都是类成员函数没法比的。而且,鉴于API中数量实在太多,于是搞出来的C++对象都是庞然大物,最臭名昭著的,当然要数CWnd和CDC这对黑风双煞了,使用起来,极不方便,极难学习。一个类的函数过多,无论如何,都是失败的设计。还有,如果WINDOWS系统新增了什么使用到句柄的函数,这些类也都要相应地增加新成员函数,再进一步说,如果用户自己因为需要,也要开发使用到句柄的全局函数,要怎么想办法整成员函数呢。其实,MFC中的所谓的线程安全,其实也不过是自欺欺人的说法而已,你要想在MFC中多线程的使用窗口对象,即使不是不可能,那也要花费九牛二力气才能在多线程中共享窗口对象,一切皆只因MFC已经很努力地做到了不让你在多线程下使用窗口对象。

        好了,再进一步考察,在这种思路的指导下,最后MFC被设计成一个什么样的框架。一直很怀疑想,MFC的设计者,是否不是对WINDOWS API的精神了解得不透彻,又或者对C++不是很精通,否则,无论如何,断断都不会整出MFC这样的一个人不象人、鬼不似鬼,精神分裂、做事虎头蛇尾的鬼东西出来。要不然,我们用MFC开发,就不会觉得束手束脚,很不好施展拳脚,一再感觉一直受制于其可恶的呆板的框架之下,这并不是说框架不好,只是MFC这套框架,实在很不好扩充。这样也罢了,问题是,MFC在使用上,又很不人性化,你又要陷入各种各样的细节之中,什么二段构造,有些对象又要自己删除,有些又不能自己删除等,更要命的是,MFC的运行效率又臭名昭著。有些同学就会问,貌似在MFC开发,其实也很强大很灵活,殊不知这种强大和灵活,那都是源于C++的强大灵活,也源于WINDOWS系统的强大灵活,源于MFC只对API只作了一层薄薄的封装,与MFC本身的设计没什么太多的关联。当抛开MFC,直接用API和C++来写代码,就体会到什么才叫做强大灵活,除了代码比MFC多一点之外,一切都要比MFC来得清爽,也要来得容易维护。如果,如果设计做得好,可能总体的代码量不会比用MFC的多也说不定。

        于是,这么一个伟大的框架,表现出来的,很多地方都C++的精神格格不入。承然,MFC刚开始设计时,缺乏太多的C++的特性的支持,而不得不另起炉灶。但是,就算没有C++98中的功能支持,MFC也不该出现以下这么重大的设计问题。
1、 不需要用到的特性,我们依然要付出种种代价。我们看到CCmdTarget集成了COM的功能,CWnd中对ActiveX的支持,就算我们的代码不包含一丁点使用到COM的代码,我们都要背负每个CWnd中将近100个字节的大小,运行过程中一再要忍受框架代码中对ActiveX变量的一次又一次地检查。我们看到,就算不使用文档视图结构,CMainFrame中都要承受对它的支持代码,和各个不必要的成员变量。总之,MFC中有很多特性,就算不愿意使用,它们还是在那里,不容许我们忽视。
2、 耦合太厉害。我们看到,CWnd中居然出现了对子类CView和CFrameWnd的引用,CControlBar的成员函数中有对CToolBar的CAST,然后,CFrameWnd又引用到CControlBar和CView,CControlBar和CView也都用到CFrameWnd的函数,各种各样好厉害的循环依赖,这么糟糕的设计竟然出现在C++的著名的界面框架,不得不令人叹息不已。这样的耦合,就是在MFC之中,一个类设计得再好,也只能在某些特定的场合下使用。好比, CControlBar, CSplitterWnd这两个好东西只能活在CFrameWnd,CView的环境下,想在其他的地方使用上就煞不容易了。就算是著名的文档视图结构,也都是问题很大,如果我的类,想要订阅文档中的通知消息,还要求必须派生于CView中,这个限制也太厉害了,于是为了它这个死板的设计,有多少次,我们必须改变设计,以适应MFC的无理取闹的要求。
3、 功能太过单薄:MFC仅仅是作为一个界面的基本框架而已,仅仅实现了从句柄到对象的映射,然后,再加上一点点所谓的文档视图的MVC模式,必要的多视图多子窗口的支持,基本的必要的COM支持,对API的薄薄封装,仅此而已(至于SOCKET、WININET和数据库的MFC类,又有多少可利用的价值)。有多少次,我们想对对话框进行拉伸的操作;有多少次,我们需要用到表格控件;……,但是,这一切,想要MFC提供更加强大的控件,完全都没有。必须求助于第三方控件公司库,好比,BCG、XTREME,你们知道,MFC的代码就算再烂,也还是很有分寸,还能保住最基本的底线,但是,第三方控件的代码,那真的是,让人大惊失色,没有做不到的,只有想不到的。要知道,C++可是很强大的,但是,用它做出来的框架,却如此的功能之小。
4、 MFC中的类的功能不单一,承载了太多的责任,导致很容易就出现了很多重复的代码:好比CCmdTarget中原本只是为了可以处理消息,后来居然还兼具COM的功能。又好比,CList, CMapPtrToPtr里面又都包含了内存池的实现代码,原本这些内存池的实现代码就应该剥离出来。
5、 行为错乱,神经分裂,没有统一的接口,以至于使用起来,极易出错。很多地方,都努力地去做了,但是都做得不彻底。企图封装所有的WINDWOWS的界面的API,但无论如何,都做不到,而且它自己内部也都知道没办法做到,但它还要努力地去做。
……

        各种各样的问题,难怪MFC的书那么多,没有一本可以作为面向对象的典范学习,即使四大天王,也不过只是没有那么恶臭而已。原来一切,皆只因为源头本就脏了。之前还以为,MFC,还能算是一积心堆砌而成垃圾。总体设计,虽然确实糟糕透顶,但细微上看,还能做到让人击节赞叹,好比对于线程局部变量的封装扩展,消息映射表。可是,即使局部代码的实现,也都充满了重重的缺陷。

        如果说MFC还有些可圈可点之处,VC2008之后引进的BCG的界面补丁,完全就将这些可稍为搬上台面的东西直接给淹没掉。BCG的出现,对MFC而言,根本就不是狗尾续貂,而是狗尾之上再绑上一只蠢笨无比的大猪。直接就将MFC推入万劫不复之地。

        MFC,OH SHIT,你可以去死了!

        突然惊觉,C++的类库框架,无不充满了各种各样的缺陷,除了STL还差强人意之外(其实也问题多多),没有一个能够让人看着满意,用着放心。于是,我要投入LISP和C的怀抱之中了,不,一定要顶住,C++是我的最爱。

posted on 2012-05-30 14:15 华夏之火 阅读(19631) 评论(47)  编辑 收藏 引用

评论

# re: MFC,一开始就错了 2012-05-30 14:56 空明流转

MFC挺好啊,C++没有自省和动态机制,GUI再怎么设计都是一团糟。  回复  更多评论   

# re: MFC,一开始就错了 2012-05-30 15:10 漂漂

楼主,改wtl吧  回复  更多评论   

# re: MFC,一开始就错了 2012-05-30 15:18 华夏之火

@空明流转
自省和动态机制确实是界面框架的利器,但是,用C设计界面,简简单单,却似乎从来都不存在这些问题。功能更丰富更强悍的C++, 起码也要实现C能做到的一切事情,并且,最后的效果,绝不能比C逊色。但可惜MFC,明显做不到  回复  更多评论   

# re: MFC,一开始就错了 2012-05-30 15:19 华夏之火

WTL也不了多少,不过是效率上去了而已,灵活性还是没有原始的C那么好@漂漂
  回复  更多评论   

# re: MFC,一开始就错了 2012-05-30 15:31 MFC彻底

一样啊!!!!都遭比尔伤惨了!  回复  更多评论   

# re: MFC,一开始就错了 2012-05-30 15:45 地里的

楼主可以尝试下Qt,我在Qt之前也是用的MFC。我个人感觉Qt设计的非常好!  回复  更多评论   

# re: MFC,一开始就错了 2012-05-30 15:51 空明流转

@华夏之火
C啊,我是不懂C哪里简单了。。。话说Framework本来就是限定性的。。。  回复  更多评论   

# re: MFC,一开始就错了[未登录] 2012-05-30 16:01 路人甲

非行班出生,连c++都没有系统的学过,只是用Qt、python分别写过小软件,对强耦合也是比较不爽的,这段时间在尝试go和lisp。特别是lisp,貌似这种去耦更适合分布式计算,最近很火的Mapreduce就是这样  回复  更多评论   

# re: MFC,一开始就错了 2012-05-30 16:20 2

1.推荐WTL
2.其次QT

WTL开源,你可以自己看着办。但很多工作还是得自己做。

QT也不错,用过,用起来挺爽的感觉。

  回复  更多评论   

# re: MFC,一开始就错了 2012-05-30 16:24 华夏之火

不好意思,说错了,C的简单是指语言层面,于是,用它设计做出来的东西,非常实在,不会让你疑神疑鬼。框架确实有局限,但MFC也管得太严了,除非对MFC太过精通,否则难以除破它的种种限制@空明流转
  回复  更多评论   

# re: MFC,一开始就错了 2012-05-30 16:26 华夏之火

QT自己搞了一套标准,还要先重新编译过,不喜欢。并且动辄十几M的库库,更加不喜欢。@地里的
  回复  更多评论   

# re: MFC,一开始就错了 2012-05-30 16:28 华夏之火

QT确实用着要比MFC爽,但我过去一直就喜欢MFC的复杂@2
  回复  更多评论   

# re: MFC,一开始就错了 2012-05-30 16:29 华夏之火

羡慕,没有用过MFC,没有经历过C++的细节纠缠折磨,幸福啊@路人甲
  回复  更多评论   

# re: MFC,一开始就错了 2012-05-30 16:43 地里的

呃……Qt官方有编译过的库。
并且你如果自己编译的话,可以使用静态库啊。
那楼主现在在Windows下做界面开发用啥玩意儿?  回复  更多评论   

# re: MFC,一开始就错了 2012-05-30 16:52 华夏之火

@地里的
很无奈,还在用MFC,公司要求,益发令人难受  回复  更多评论   

# re: MFC,一开始就错了 2012-05-30 18:14 Richard Wei

哈哈,恭喜,博主终于醒悟了  回复  更多评论   

# re: MFC,一开始就错了 2012-05-30 19:22 bigbug

您妈,MFC shit,C++难?吃屎容易  回复  更多评论   

# re: MFC,一开始就错了 2012-05-30 19:54 钟谢伟

那么久的MFC历程,如果要让你静下心来,写一篇赞扬MFC的文章的话,会怎么样呢,很期待。怎么说事情都是有两面性的,并且它在市场上流行了那么多的年头。其实本人没咋接触过MFC,在选择gui设计的时候,最初选择的是直接调用api,后来选择的是wxwedget(入门)的。时代总是在变,库也应该是与时俱进的,不过它还有适合使用的地方吧。
一个不熟悉MFC的人辩证的看法。  回复  更多评论   

# re: MFC,一开始就错了 2012-05-30 20:33 墨魂

当初学C++的时候,最后一次老师说如果没学MFC,那C++就算白学了。当初我没有怀疑这句话,然后就去学了。看了一个月的MFC,第一个例子我怎么也弄不明白。感谢我的偏执,能彻底摒弃WINDOWS的一切。在LINUX上,学QT,一个月,我差不多能熟练运用。这世界上有天才,就有天生优秀的设计。更何况在开源世界里,是无数的天才。  回复  更多评论   

# re: MFC,一开始就错了 2012-05-30 21:55 远行

我mfc也用了很久,除了大一的c语言课程设计,以后基本所有的实验,课程设计,项目全部是mfc做的界面。mfc应该算用得比较熟悉了,四大名著也看了2本左右,不过看了之后还是忘了。感觉真心学设计还是先用吧,要不然即使看了设计还是会忘记的。mfc确实不怎么好用,甚至比算法还难用。我学算法也比较多,至少熟悉的算法我不用查文档能写出来,但是用了这么久的mfc,如果没有google和csdn,我很多程序的功能根本做不出来,只是翻msdn连地方都很难找。至于看书的数目的话,我也不会少,我翻书速度很快,关于mfc的书看过至少不下8本,如lz所说,看那些书,要么就是浪费时间,要么就是看不懂还是浪费时间,很多mfc的书都是shit,除了四大名著。
也不要说我c++和Windows编程的知识很烂,大一暑假就啃完c++primer了,大二第一学期看的Windows程序设计,几年下来,msdn,csdn之类的都翻了不知道多少次了。。。mfc的代码也真的不少了,如果mfc真的好用的话,我至少不应该这么依靠google强悍的搜索能力。而且,到最后基本找到的出处是csdn和别人的博客。。。
界面这个东西本来就扯淡,但是个人认为在Windows做界面,还是了解Windows程序设计的基本原理最重要,用不用mfc倒是其次。用mfc学设计应该
还不错,真心希望多一些伟大好用的界面库给大家用,谁都不想麻烦。。。  回复  更多评论   

# re: MFC,一开始就错了 2012-05-31 01:39 华夏之火

要我说MFC的好话,还真不容易呢。但好话,基本上四大天王已经说尽了,你要是感兴趣,可以看看@钟谢伟
  回复  更多评论   

# re: MFC,一开始就错了 2012-05-31 01:42 华夏之火

阁下很明智。嘿,你们的老师,那真是,不过大学里的老师,基本上都是这样@墨魂
  回复  更多评论   

# re: MFC,一开始就错了 2012-05-31 01:47 华夏之火

有道理。我们为什么要对MFC如此责备求全,实在是因为如果不精通MFC,就没办法做出似模似样的东西,但当你一次又一次深入地学习MFC的源码之后,就会对它很失望。一个框架,如果要求用户必须精通它,才能用得好,那真的是很失败@远行
  回复  更多评论   

# re: MFC,一开始就错了 2012-05-31 15:01 codejie

想想咱不用MFC多少年了。。。wxWidget也是个选择。。。  回复  更多评论   

# re: MFC,一开始就错了[未登录] 2012-06-02 01:40

mfc1.0在92年发布,别说C++标准了,连dynamic_cast、异常都没有。
在那么恶劣的情况下搞出20年结构都没啥变化的类库,可见设计者多么nb。
对于耦合度,基本上在那个框架上开发都得遵守框架上的要求,继承某些类,耦合某些类。  回复  更多评论   

# re: MFC,一开始就错了 2012-06-02 02:08 华夏之火

可是,我要说的是,即使没有异常、dynamic_cast、type_info、template,甚至连虚函数都没有,都可以写出比MFC更好的框架@坏
  回复  更多评论   

# re: MFC,一开始就错了[未登录] 2012-06-03 01:02

@华夏之火
啥框架?  回复  更多评论   

# re: MFC,一开始就错了 2012-06-04 15:42 zjh

GTK+  回复  更多评论   

# re: MFC,一开始就错了 2013-02-25 02:42 FrankWei

特喜欢这文章,每每戳中笑点,嘎嘎~  回复  更多评论   

# re: MFC,一开始就错了 2013-06-17 15:23 panovr

挺好的文章。本来只是使用MFC,却经常需要去看MFC的源代码。  回复  更多评论   

# re: MFC,一开始就错了 2013-06-18 11:09 panovr

为什么这样说:“而VC2008中BCG的出现之后,VC2010还依然保留着那些蠢笨无比的BCG文件,不思悔改,终于让某彻底对MFC死心了,这货没得救了。”?  回复  更多评论   

# re: MFC,一开始就错了 2013-11-04 19:52 红色代码

文中的大侠指的是云风吧?MFC我也用了至少4年,接触了WTL之后,就再也不想碰MFC了.太臃肿了,不过里面的好多东西 还是值得学习的.虽然浪费了不少的时间,但是不后悔  回复  更多评论   

# re: MFC,一开始就错了[未登录] 2013-11-08 16:23 Aaron

非常欣赏!  回复  更多评论   

# re: MFC,一开始就错了 2013-11-22 10:05 SuperCPlusPlusSystemAna

C++,MFC依然是顶级开发人员的王者工具;一个C++老兵如是的说....  回复  更多评论   

# re: MFC,一开始就错了 2013-11-22 10:12 SuperCPlusPlusSystemAna

来北京10年了,多少同事飞灰烟面,我依然能够感受到公司对C++核心开发人员的仰慕和尊重,那是发自肺腑的对王者程序员的尊重, 原因很简单,MFC也依然是程序开发领域中,多少后来者不可逾越的领域,千万不要夜郎自大,那是因为你的水平依然还不够.  回复  更多评论   

# re: MFC,一开始就错了 2014-02-21 22:30 Mr A

任何让用户不专注于事物本身,而要去专注于工具本身的东西都是流氓  回复  更多评论   

# re: MFC,一开始就错了[未登录] 2014-02-27 11:45 Steven

说的非常在理,很赞!  回复  更多评论   

# re: MFC,一开始就错了 2014-03-05 15:20 喷傻缺

@钟谢伟
呵呵,与时俱进?
看看已经是半个世纪的C、C++,人家玩了10多年了依然活得有滋有味,而那些所谓的高级语言呢?一两年就换框架就得从头学习,这叫与时俱进?傻缺还差不多。
傻缺到养活那些所谓的高级IDE公司被卖了还帮人家数钱。
10年的C++经验累计足以精通,10年VS几度更改几度学习,精通你妹,10年后你还是唯有不停的买不停的学。傻缺!!!还与时俱进!!!!  回复  更多评论   

# re: MFC,一开始就错了[未登录] 2014-03-23 14:54 菜鸟

没有楼主说的那么糟糕吧。取你需要的开发,又没有让你把MFC都玩一遍;如果你从中获得了你需要的,管他MFC,QT什么的,又有多大差别呢?  回复  更多评论   

# re: MFC,一开始就错了 2014-04-19 23:51 闻德鹏

爱越深,恨越深么
哎~~~  回复  更多评论   

# re: MFC,一开始就错了 2014-12-17 17:26 路过

从仰望到批判是境界的提升,单看MFC孵化出了多少能够批判她的猿,贡献还是蛮大的。  回复  更多评论   

# re: MFC,一开始就错了[未登录] 2015-05-25 10:53 小龙

傻x,这么伟大著作起始二等小辈随便乱叫的  回复  更多评论   

# re: MFC,一开始就错了 2016-03-14 15:26 potato

看过programming windows with mfc 2ed, window programming 5th 吗? 有没有扩展过mfc 的默认控件 , 如果没有, 只会抄代码, 那你只有刚入门, 你说的BGC是什么写的 , 看看源代码就知道, 虽然mfc 编写代码要较长时间, 但这个提供了最基本的工具, 你可以创造啊, 总之一句话, 你嫌mfc 麻烦, 要花好长时间学习, 拿别人做好的, 很爽。  回复  更多评论   

# re: MFC,一开始就错了 2016-05-03 14:38 intel

楼主没用过 ultimate MFC win31  回复  更多评论   

# re: MFC,一开始就错了 2016-05-10 08:19 呵呵

MFC就是垃圾,要不是微软力推早完蛋了,一堆烂宏堆积代码,没法维护。QT貌似是个不错的选择。WTL太小众,wxWidget用的也太少,商业用啊,人得吃饭啊。GTK+那代码没法看,我觉得C就不适合做界面。所以还是QT吧,无论PC还是嵌入式,尤其嵌入式。  回复  更多评论   

# re: MFC,一开始就错了 2016-05-10 09:55 华夏之火

@呵呵
以90年代的标准来看,mfc还是很不错的。那个时候没有template,没有exception,业界对于面向对象的思考也没那么深刻。以那时的标准c++,没有编译器扩展,mfc真是相当不错  回复  更多评论   

# re: MFC,一开始就错了 2016-07-19 15:55 rita

QT挺不错的,消息机制很灵活,封装的也比较好,让人感觉自己确实是使用框架而不是跟框架内部较劲
大学学c++以后要求我们自学界面库做大程,别人几乎都选的mfc,就我选的QT,那学习效率真的没得说,后来又再自学mfc,感觉自己从现代社会进入了原始社会【。  回复  更多评论   


只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理


导航

统计

常用链接

留言簿(6)

随笔分类

随笔档案

搜索

积分与排名

最新评论

阅读排行榜

评论排行榜