从深度和广度谈C++的复杂度

C++到底有多复杂,没有人知道,我们知道的,只是C++很复杂。但是再复杂的事情也有解决的方法,对于C++的复杂度,我们可以从C++的“深度”与“广度”来探究。

C++有一个朴素的思想:“简单的问题用简单的方法解决,复杂的问题,用复杂的方法解决。”。这句话当然不能绝对化。一个问题的复杂性,往往有多种来源,比如可以是“深度”上的困难;从这一点上,我们了解,证明“任何一个>=6之偶数,都可以表示成两个奇质数之和 ”是个难题,虽然题目很短一读明白,但它确实是一个复杂的问题,因为它是“哥德巴赫猜想”。

复杂度的来源也可以是问题的“广度”。比如给一个人做一道可口的菜是简单的,但今天是周末,我家来了七大姑八大姨,站在厨房里的我就会感觉面临一道复杂的问题。我不仅要了解每一位亲人的口味,并不绝不能做八道菜,让客人各选所需就算了。八个简单的问题,交叉在一起时,成就了一道“众口难调”的复杂的问题。

C++中所具备的复杂功能,一小部分有助于我们解决深度上的复杂问题,但更多的功能,是为用来对付“广度”上问题。这符合软件开发行业的主要市场需求。

小结一下:C++中有很多复杂的(方法或)知识点其实是留着对付一些复杂问题的。但,我们在学习C++时,我们能遇上什么“复杂”问题吗?答:很少,甚至就是没有。那么,光靠一些简单的问题,我们能理解那些复杂的方法吗?

比如“面向对象”。C++之父早说过,C++语言不是,也不愿意成为一门单纯的“面向对象”的语言。为什么?因为“简单的事情简单解决。”,“面向对象”的编程思想,在历史上出现,就是为了解决足够庞大的复杂问题才提出,并且确实取得了一定程度上的成功。于是乎人人都对它趋之若骛,更是成为了大学编程专业的必修课。但请问,你根本就没可能在书本上遇上任何足以体现“面向对象”之必要性的问题,你怎么学习“面向对象”呢?请注意,写一个“非常面向对象”的程序,是很容易地,一个java版本的“Hello world”程序就很OO。但把程序写得非常有“面向对象”的风格,这绝对不是我们的目标。目标是解决问题,“面向对象”是一种“思想工具”,当我们判断再没有更简单的工具来解决一个问题时,于是把手伸入机器猫的口袋,叮叮铛……屏幕上打出四个大字“面向对象”。

有同学要举手反对了,复杂度是相对啊。一个在大拿眼里,很简单的,用面向过程可以非常漂亮地解决的问题,但在初学者面前,就是一个大广度的问题,这时,作为一种组织方法,“面向对象”不能帮我们些什么吗?如果能帮上,那我们用它来学习“面向对象”,就不算是纸上谈兵了吧?

完全同意。像Linus这样的大牛,操作系统这样既深又广的问题,他都觉得用C语言这样典型的面向过程的语言,就可以轻易拿下,他倒觉得像C++这样的语言的OO,纯是添乱。

复杂度当然是相对的,但当我们面临,或者说期望的复杂是指“广度”上的复杂度时,普通教程上的那种一杆子想把C++语言捅到底的教学内容与教学方式,就显得非常的不够用了。写一个“俄罗斯方块”的程序,就是一个“相对复杂”的问题。翻开一本《C++ Primer》,740多页,如果仅仅从C++语言知识点来看,任何一个学到第227页的读者,都应该要开始动手写一个俄罗斯方块的程序。因为那时候他已经懂得多维数组,于是可以定义出方块数据;他已经懂得if判断,于是写得出碰撞判断;他已经学会for循环,于是知道如何消掉被填满的一行或多行……

有人觉得我这是“忽悠”。他们又改口说,“俄罗斯方块”是一个太复杂的问题了,如果学生在学习半途花上一个月时间去搞一个俄罗斯方块,会节外生枝,彻底打乱原来学习计划云云。好吧我承认确实存在苦研十年军事理论,然后杀上战场一举成名的将军;但我更愿意相信多数将军是不断地打一场场小战役,不断地在晚上挑灯看《武穆遗书》的过程中成长起来的。而我也确实看到那些在一个月中,被“俄罗斯方块”程序搞得头破血流,并坚持下来的学生,确实在日后遇上问题时,有着更好的“纠缠”能力。试想一下吧,学完《C++ Primer》200多页时,像样的问题都没遇上一个,却要再翻过那么一百多页,然后开始学习“第三部分 类和数据抽象”。

我用《C++ Primer》当教材当老师,不是一次两次了,但每当我开始兜售“面向对象的本质不是封装、不是派生、不是多态,而是抽象”时,我总觉得自己是那么无力。底下的战士,他们没有打过任何一场像样的战役,但他们希望在课堂上成长为巴顿,成长为陈庚。

在那一时,我总会想起C++之父痛心地说到C++教育的一句话,大意是说:现在C++教育似乎进入了一个怪圈:要教会一个人C++,唯一的办法,就是把他教成C++高手。我在从事C++教育时,很长时间,发现自己一样落在怪圈里!长叹。

(以上内容,任何有正常理智或心态的人,都不会认为:本文作者在说《C++ Primer》是一本差书。)

对一个初学者,学完《C++ Primer》227页之后,动手写一个俄罗斯方块游戏,复杂在哪里?

(一),C++初学者(没有其它语言学习经验)那时刚刚把类型、变量、数组、指针、if、for………装入脑里,每一个知识点都才刚刚开始消化,这时要把这一切掺合到一起,去解决一个真正的问题,就像一个刚刚看完《高尔夫球杆使用说明》的人上了场,那个乱劲儿!

(二),没有人会觉得写一个字符界面的俄罗斯方块很爽,所以总得要去碰一下图形用户界面的编程知识吧。窗口、菜单、定时器、消息、GDI,资源文件……妈啊。就这一点就够广的。

(三)、教材里那些花花草草小猫小草的例程,也确实拿来过调试,什么单步跟踪、什么断点、什么变量观察……还有什么条件编译、二分法、以及如何使用Windows的调试API,比如“OutputDebugString”函数等等,平常老师在台上讲,我们都觉得需要那么多调试方法吗?现在可好,程序好不容易编译通过,一运行就死了,一头雾地才开始想如何调试……

公元一九八九年,有人问总设计师说中国十年改革开放最大的失误是什么?他说是教育。(公元2008?)有人问C++之父,十数年,C++语言最大的失误是什么?Stroustrup说,也是教育。这个“也”字纯属我加的。原文得是这样:

Stroustrup Says C++ Education Needs To Improve :

“在C++的早期,我很担心不能足够快的教好教师。我有理由担心,因为许许多多明显的C++的错误使用都可以追踪到教育者自身对基础的误解。我未能足够清晰的阐述我的想法和原理。”Stroustrup表示,“我避免传授‘如何思考’,我猜想最好的教育之法是使用大量优秀的例子。”

没错,如果可能,就永远别去教学生如何“面向对象”,而是要让他们陷在问题的海洋里,再加上有力的引导,最终让他们自己悟出面向对象的真谛。

如果我有儿子。当他成长到对爱情似懂非懂的青涩年龄时,我不想对他讲一堆什么爱情啊责任啊的大道理。我也不希望他谈第一个女朋友,就马上顺利地步入婚姻,我希望如果可能,他最好遇上些嫌贫爱富的女人,遇上些虚荣乖张的女人,然后被女人抛弃过,或抛弃过别人,然后命运再安排他遇上他的灰姑娘。

花花公子,情海里几度沉浮,不轻易付出感情的男人,通常比那些遇上第一个女人就爱得死去活来的青涩男孩,更懂得爱情的真谛,在婚后也往往更不会爱上别的女人。为什么,因为随便碰上个异性就爱得死去活来的人,通常他们爱的不是人,他们爱的是“爱情”这个东西,就算他们其实没有足够了解爱情中另一个人。

作为C++程序员,碰上任何一个问题,就要来扯上一通“面向对象”如何如何的人;在碰上真正问题时,往往比那些懂得简单问题简单解决的人,挂得早。因为他们的出发点是爱上了“面向对象”,而不是了解所要解决的问题。

同样的,作为一个C++爱好者,你可以爱上C++,但作为一个程序员,请别轻易说,我爱上了一门语言。爱容易让人盲目;一个盲目的fans,是有力量的,他全身心地投入了学习,真好;但一个盲目的程序员,是可怕的,他会以为,C++和爱情一样,无所不能。

但具体到我个人,我有我的坚持,我决不愿意把我的学生培养成C++的粉丝(但,成为C++之父BS的粉丝,我热烈支持:)。相反,我会“折磨”他们,《白话 C++》中的第二章《准备》,已经成功地让很多学习者,发出哀怨:“学习C++,有必要去安装、编译这么多库吗? 还是Java好,一切都准备好了。”

《准备篇》的绪言,是一句煽情的话:“决定你能否成为程序员,不在于你的计算机基础,在于你是否有足够的耐心。”

现在社会,有些女人或男人,会同时和几个异性谈恋爱,他们是势利的。我当然也反对这种不道德的行为。但如果是学习语言(无论是编程语言或自然语言),如果你有能力,我建议完全可以同时学习两门,学习上越“势利”越好,而有能力时,同时学习多门语言,那是相当的有利可图,具体有机会再展开。通常一个人对在C++语言熟练之后,就具备了这个能力。对于从没有学习过其它编程语言的初学者,同时学习C++语言之外,还要学习另一门,不现实。但是,当我们仅仅限定C++编程的范畴,那就一定不能痴痴,长期地把精力和爱心都放在语言自身上。

C++之所以复杂,是因为C++的“深度”与“广度”都很深远,但是遵循“有一定深度,扩大广度,有一定广度,加深度”的方法,会发现C++的“深度”与“广度”会成为我们编程中的一点乐趣。希望本文会给读者带来收获。

【编辑推荐】

  1. C++学习重点分析
  2. 解析C++和C的区别
  3. C++的明天是否会依旧辉煌?
  4. 浅谈C++调用C#的DLL程序方法 
THE END