你应当如何学习C++(以及编程)
关键要了解那些重要的思想(很长时间不变的东西),而不是很细的技术细节(易变的东西)。
学C++之人有一种类似于被暗示的潜在心态,就是一定要先把语言核心基本上吃透了才能下手写出漂亮的程序。这首先就错了。这个意识形成的原因在第二点,C++书籍。市面上的C++书籍不计其数,但有一个共同的缺点,就是讲语言细节的书太多——《C++ gotchas》,《Effective C++》,《More Effective C++》,但无可厚非的是,C++是这样一门语言:要拿它满足现代编程理念的需求,尤其是C++库开发的需求,还必须得关注语言细节,乃至于在C++中利用语言细节已经成了一门学问。比如C++模板在设计之初根本没有想到模板元编程这回事,更没想到C++模板系统是图灵完备的,这也就导致了《Modern C++ Design》和《C++ Template Metaprogramming》的惊世骇俗。这些技术的出现为什么惊世骇俗,打个比方,就好比是一块大家都认为已经熟悉无比,再无秘密可言的土地上,突然某天有人挖到原来地下还蕴藏着最丰富的石油。在这之前的C++虽然也有一些细节,但也还算容易掌握,那可是C++程序员们的happy old times,因为C++的一切都一览无余,everything is figured out。然而《Modern C++ Design》的出世告诉人们,“瞧,还有多少细节你们没有掌握啊。”于是C++程序员们久违的激情被重燃起来,奋不顾身的踏入细节的沼泽中。尤其是,模板编程将C++的细节进一步挖掘到了极致——我们干嘛关心涉及类对象的隐式转换的优先级高低?看看boost::is_base_of就可以知道有多诡异了。但最大的问题还在于,对于这些细节的关注还真有它合适的理由:我们要开发现代模板库,要开发active library,就必须动用模板编程技术,要动用模板编程技术,就必须利用语言的犄角旮旯。
然而,如果仅仅是因为要开发优秀的库,那么涉及这些细节都还是情有可原的,至少在C++09出现并且编译器厂商跟上之前,这些都还能说是不得已而为之。但我们广大的C++程序员呢?大众是容易被误导的,我也曾经是。以为掌握了更多的语言细节就更牛,但实际情况却是那些语言细节十有八九是平时编程用都用不到的。C++中众多的细节虽然在库设计者手里面有其用武之地,但普通程序员根本无需过多关注,尤其是没有实际动机的关注。一般性(《代码大全》TP311.52/171)的编码实践准则(《C++ Coding Standards: 101 Rules, Guidelines, and Best Practices》),以及基本的编程能力和基本功(《深入理解计算机系统》TP3/124.1),乃至基本的程序设计理论(《计算机程序的构造和解释》TP311.1/216)以及算法设计(《算法导论》)。才是真正需要花时间掌握的东西。
学习最佳编码实践比学习C++更重要。看优秀的代码也比埋头用差劲的编码方式写垃圾代码要有效。直接、清晰、明了地表达意图比玩编码花招要重要……
避免去过问任何语言细节,除非必要。这个必要是指在实际编程当中遇到问题,这样就算需要过问细节,也是最省事的,懒惰者原则嘛。一个掌握了基本的编程理念并有较强学习能力的程序员在用一门陌生的语言编程时就算拿着那本语言的圣经从索引翻起也可以编出合格的程序来。十年学会编程不是指对每门语言都得十年,那一辈子才能学几门语言哪,如果按字母顺序学的话一辈子都别指望学到Ruby了;十年学习编程更不是指先把语言特性从粗到细全都吃透才敢下手编程,在实践中提高才是最重要的。
至于这种抠语言细节的哲学为何能在社群里面呈野火燎原之势,就是一个心理学的问题了。想像人们在论坛上讨论问题时,一个对语言把握很细致的人肯定能够得到更多的佩服,而由于论坛上的问题大多是小问题,所以解决实际问题的真正能力并不能得到显现,也就是说,知识型的人能够得到更多佩服,后者便成为动力和仿效的砝码。然而真正的编程能力是与语言细节没关系的,熟练运用一门语言能够帮你最佳表达你的意图,但熟练运用一门语言绝不意味着要把它的边边角角全都记住。懂得一些常识,有了编程的基本直觉,遇到一些细节错误的时候再去查书,是最节省时间的办法。
正确的态度是,细节是必要的。但细节是次要的。其实学习编程我觉得应该最先学习如何用伪码表达思想,君不见《算法导论》里面的代码?《计算机程序设计艺术》中的代码?哦,对了,它们是自己建立的语言,但这种仅教学目的的语言的目的就是为了避免让写程序的人一开始就忘了写程序是为了完成功能,以为写程序就是和语言细节作斗争了。
一旦建立了正确的学习编程的理念,其实什么书(只要不是太垃圾的)都有些用处。都当成参考书,用的时候从目录或索引翻,基本就对了。
学习C++的意义其实真的是醉翁之意不在酒,像C/C++这种系统级语言,在学习的过程中必须要涉及到一些底层知识,如内存管理、编译连接系统、汇编语言、硬件体系结构等等等等知识(注意,这不包括过分犄角旮旯的语言枝节)。这些东西也就是所谓的内功了(其实最最重要的内功还是长期学习所磨练出来的自学能力)。
所以,答案是,让你成为高手的并不是你掌握什么语言,精通C++未必就能让你成为高手,不精通C++也未必就能让你成为低手。所以关键的不是语言这个表层的东西,而是底下的本质矛盾。学语言是一个途径,如果你把它用来磨练自己,可以。如果你把它用来作为学习系统底层知识的钥匙,可以。如果你把它用来作为学习如何编写优秀的代码,如何组织大型的程序,如何进行抽象设计,可以。如果掉书袋,光啃细节,我认为不可以(除非你必须要用到细节,像boost库的coder们)。
一句话:我们得把时间用于学习解决本质困难。新技术给高手带来方便。菜鸟们却不用指望被新技术拯救。沿用以前的比喻, 一流的摄影师不会因为相机的更新换代而丢掉饭碗,反而可能借助先进技术留下传世佳作。因为摄影的本质困难,还是摄影师的艺术感觉。热门技术也就等于相机。 不停追新,学习这个框架,那个软件,好比成天钻研不同相机的说明书。而热门技术后的来龙去脉,才好比摄影技术。为什么推出这个框架?它解决了什么其它框架 不能解决的问题?它在哪里适用?它在哪里不适用?它用了什么新的设计?它改进了哪些旧的设计?选择学习内容是非常重要的。必须学习 本质技艺,因为技术迟早过时,技艺却常用长新。C/C++过时就过时了呗,只要有其它的系统编程 语言。Java倒了就倒了呗,未必我不能用.NET?Ruby昙花一现又如何。如果用得不爽,换到其它动态语言就是了。J2EE被废了又怎样?未必我们就 做不出分布系统了?真正的专业技能融入我们的直觉,不会过时。过时的不过是可以被完整封装的琐碎操作。我们应当拥抱先进的工具,任由那些琐碎操作过时。
诚然,C++非常复杂。诚然,人们迷失其中了。然而问题是,大多数人不是因为首先对自己想要表达什么有了清晰的认识只不过在去C++语言中搜寻合适的语言特性时迷失的,相反,大多数人是在不觉成为语言律师的路上迷失在细节的丛林中的。事实上,只需对数据抽象、类体系结构(OOP)以及参数化类型(GP)有一个相当一般层面的了解,C++纷繁的语言特性也就清晰起来了。
一些非常基本的功夫(如计算机体系结构、数据结构和算法、两个主要流派(命令式和声明式)的编程语言都使用了哪些主要的编程范式、对主流语言的优缺点和适用场合的了解等等)是必须掌握牢靠的。
C++的书,Bjarne的圣经《The C++ Programming Language》是高屋建瓴的。《大规模C++程序设计》是挺务实的。《Accelerated C++》是最佳入门的。《C++ Templates》是仅作参考的。《C++ Template Metaprogramming》是精力过剩者可以玩一玩的,普通程序员碰都别碰的。《ISO.IEC C++ Standard 14882》不是拿来读的。Bjarne最近在做C++的教育,新书是绝对可以期待的。
系统编程。Windows下推荐两本书——《Windows 程序设计 》和《Windows核心编程》,Unix/Linux下推荐两本书——《Unix高级环境编程》和《Unix网络编程卷1,套接字》《Unix网络编程卷2,进程间通信》尤其是《Unix网络编程》这本书,一通百通,无论Windows还是Unix/Linux,都是一样的。
系统设计。关于设计方面,我全力推荐《Unix编程艺术》,看完以后,你就明白什么是真正的编程文化了。然后,当你看到Windows的Fans的某些言论时,你就知道什么叫一笑了之了。
- 编程编到一定时候,你就需要了解底层系统的机制,否则,知其然不知所以然。
- 我没有否定非C的程序员的逻辑,真正的逻辑是——如果你想要了解底层机制,请学习C语言和操作系统。
- 40多年的Unix/C影响深远。包括影响了Windows。如果你想一通百通,一定要了解Unix。那是计算机文化真正的根。
- 不要肤浅地去思考问题。比如,不要以为一个DBA就不会考虑数据库引擎的内存页面的问题。也不要以为Web程序员就不需要了解后台的服务器和脚本的运行性能以及TCP/IP的问题。
高手往往都是有很强的系统的基础知识的,表面的东西永远是肤浅的。