●困难度之一
「C++ 是个难学易用的语言」,这句话相信很多人心有戚戚。C++ 的学习难度,一在於语言本身太多的「幕」,一在於 "paradigm shift" (思考模式的移转)。
传统循序语言如 C, Pascal, Basic, Fortran...,除了模样看起来稍有不同,基本上都是函式 call 来 call 去,大同小异,很容易掌握。你想做的动作,在 code 中都看得一清二楚。你所看不到的,荦荦大者也不过就是编译器为你的函式加上用以处理堆叠的一小段码(prologue 和 epilogue),这一小段码基本上做的是 housekeeping 工作,你没看到也没有关系(更好),并不影响你对程式逻辑的思考。
C++ 不一样,C++ 有太多和程式逻辑息息相关的动作是编译器为我们加上去的。换句话说 C++ 编译器为我们「加码」。如果不识清这一节,学习C++ 有如雾里看花,雾非雾,花非花。
编译器为我们的 C++ 程式加了什麽码呢?很多!物件诞生时 ctor 会被唤起,物件死亡时 dtor 会被唤起,这都是加码的结果。ctor 中设定vtpr 和 vtbl,这也是加码的结果。new 单一物件时会产生 memory block cookie,new 物件阵列时会产生一个内部结构记录着 object size 和 class ctor...,这也都是布幕後的工作。可以说,程式码中看不到而却必须完成的所有与程式逻辑有关的动作,统统都是 C++ 编译器加码後的结果。
当「继承」发生,整个情况变得稍微复杂起来。「多重继承」又更复杂一些,「虚拟继承」再更复杂一些。
这些布幕後的主题,统可归类为所谓的 C++ object model(物件模型)。如果不知道这些底层机制,你就只能够把 "make destructors virtual in base classes"(<Effective C++>, item14)或 "never treat arrays polymorphically" (<More Effective C++>, item 3)这类规则硬背下来,却不明白它的道理。
用一样东西,却不明白它的道理,林语堂如是说:『不高明』。只知道 how,不知道 why,侯捷如是说:『不高明』。
●困难度之二
C++ 的第二个学习难度在於 "paradigm shift"(思考模式的移转)。别说自己设计 classes 了,光使用别人的 classes,就都是一种思考模式和行为模式的移转。MFC(或 OWL 或 VCL)programmer 必然甚能够领略并体会我的意思。
使用所谓的 application framework(一种大型的、凝聚性强的、有着物件导向公共基础建设的 class library),你的码和 framework 之间究竟是怎样的关系呢?framework 提供的一大堆可改写的虚拟函式的意义与价值究竟在哪里呢?为什麽 framework 所设计的种种美好性质以及各式各样的演算法竟然可以施行於我们自己设计的 class types 身上呢?framework 被设计时,并不知道我们的存在呀!
这正是物件导向中的多型(polymorphism)的威力。
稍早所说的 C++ 物件模型,偏属程式设计的低层面;这里所说的思考模式移转,则是程式设计的高层面。能够把新思维模式的威力发挥得最淋漓尽致的,当推物件导向的polymorphism(多型)和 generalization(泛型)。如果你没有使用这两项特性,等於入 C++ 宝山而空手返。
●反覆炼,循环震荡
想像 C++ 是一把用来解决程式问题的刀,要它坚轫,要它锋利,就必须经过多次的回火,在高热和骤冷之间炼。
初学 C++ 语法(syntax)之後,你应该尽快尝试体验 polymorphism (大致而言也就是虚拟函式的运用)。等到对 OOP 的精神有了大局掌控的能力,但对 C++ 的许多小细节不甚清楚,就是回到C++ 物件模型炼的时机。
成长,是在高阶(polymorphism)和低阶(object model)之间反覆震荡,才能够震荡到更高的位阶,而不是平平庸庸於中阶(C++ syntax)的一滩死水。
●不要沉沦於 C++ syntax
100 个人跟我说他懂 C++/OOP,只有 10% 不到可以让我认为他没有胡吹大气。太多的人,上嘛上不到 polymorphism,下嘛又下不到object model。就这样不上不下地卡在 C++ 语法层面。大一学了C++,到大四快毕业了,连 virtual functions 是怎麽回事都期期艾艾支支吾吾说不出个道理。
有时候我觉得,太苛责同学也於心不忍,因为同学们事实上处於一种无知的状态,既不知道 C++/OOP 该怎麽学,也不知道哪些书可以教他们那麽学。所以,苛责同学,不如责怪老师。
众所周知,大学教授泰半是动口不动手,普遍的心态是「论文第一,升等为要;程式语言?哎,末流!」。「末流」课程通常由教授们轮流教,谁倒楣谁来教;於是就常常有「下学期要教 C++ 语言了,这学期寒(暑)假赶快去要本书来恶补」的情况发生。偏偏程式语言这东西,只动口不管用,一定要动手,而且要常动手。老师自己没有摸到C++/OOP 的精神,学生又能学到什麽?
有些学校资讯系并不教特定的程式语言,老师们的态度是「语言是一种自己学就好了的东西嘛,拿到大学殿堂来,哎,不入流」!於是应该好好为学生打下实际基础的课程,却天马行空地腾云驾雾起来,大谈抽象意念。饱读经书的老师们可能忽略了,一个完全没有技术基础的学子,要的不是形而上的道,而是形而下的器。
我们是先能够欣赏具象画,还是先能够欣赏抽象画?我们不都是先对毕卡索的画大骂「这是什麽东西」,直到自己的艺术涵养够丰富了、人生阅练更饱满了、能够举一隅以三隅反了、能够接触类旁通左右逢源了,才转而能够欣赏甚至进入毕卡索的抽象意境吗?
老师们各有专长,要老师们来教非彼专长的大班课、基础课,我又觉得似乎也太为难老师了。那麽,苛责老师,不如责怪学校当局。如果学校当局能够聘请经验老道又有教学热诚的工程师来教这类实务学科,不是三方皆大欢喜吗?不要说什麽制度僵化啦,难以突破啦,大学是高度自治区,礼聘几位兼任老师,不全都是系上的权责范围内吗?
当学子们在课程上学不到他要的东西,就只好闭门自修。但是,循序性(sequential)语言尚有自修学会的可能,物件导向语言嘛,以大学生的程度来讲,我认为自修实在困难,只会修出个四不像、半瓶水。
管不到学校!管不到教授!自求多福的情况下,希望看到这篇文章的你,知道 C++/OOP 该怎麽学。
延伸阅读
文章来源于领测软件测试网 https://www.ltesting.net/