對C++教程寶典進(jìn)行解析
一旦我們認(rèn)識(shí)了C++在一些領(lǐng)域是有需求的(值得學(xué)習(xí)和掌握的)這個(gè)問題之后,就可以接下來討論“怎樣正確學(xué)習(xí)和掌握C++”這個(gè)核心問題了。
其實(shí),對于這個(gè)問題,Bjarne已經(jīng)宣傳了十年。早在99年的時(shí)候Bjarne就寫了“Learning C++ as A New Language”,并在好幾篇技術(shù)訪談(這里,這里,這里,還有這里)里面提到如何正確對待和使用C++中支持的多種抽象機(jī)制的問題。Andrew Koenig也寫了一本現(xiàn)代C++教程《Accelerated C++》(這本書后面還會(huì)提到)。然而這么多年來,C++社群的狀況改善了嗎?
就我所知,就算有改善,也是很小的。學(xué)習(xí)者還是盲目鉆語言細(xì)節(jié),只見樹木不見森林;網(wǎng)上還是彌漫著各種各樣的“技術(shù)”文章和不靠譜的“學(xué)習(xí)C++的XX個(gè)建議”;一些業(yè)界的有身份的專家還是在一本接一本的出語言孔乙己的書(寫一些普通程序員八輩子用不著的技巧和碰不著的角落);而業(yè)界真正使用C++的公司在面試的時(shí)候還總是問一些邊邊角角的細(xì)節(jié)問題,而不是考察編程的基本素養(yǎng)(不,掌握所有的語言細(xì)節(jié)也不能讓你成為一個(gè)合格的程序員)。
這個(gè)面試?yán)砟钍清e(cuò)誤的,估計(jì)其背后的推理應(yīng)該是“如果這個(gè)家伙不知道這個(gè)細(xì)節(jié),那么估計(jì)他對語言也熟悉不到哪兒去;而如果他知道,那么雖然他可能并不是好的程序員,但我們還是能夠就后一個(gè)問題進(jìn)一步測試的”,這個(gè)理念的問題在于,對語言熟悉到一定程度(什么程度后面會(huì)具體建議)就已經(jīng)可以很好的編程了(剩下的只需查查文檔);
而很多公司在測試“對語言熟悉程度”的時(shí)候走得明顯太遠(yuǎn)了(比如,問臨時(shí)對象生命期和析構(gòu)順序當(dāng)然是無可厚非的,但問如何避免一個(gè)類被拷貝或者如何避免其構(gòu)建在堆上?);當(dāng)然,有些語言知識(shí)是必須要提前掌握的,具體有哪些后面會(huì)提到,面試的時(shí)候并非不能問語言細(xì)節(jié),關(guān)鍵是“問哪些”。
所以說:
事實(shí)3:C++的整個(gè)生態(tài)圈這么些年來在學(xué)習(xí)C++的哲學(xué)上,實(shí)在沒有多少改善。
為什么?是因?yàn)锽jarne介紹的學(xué)習(xí)方法在技術(shù)上沒有說到點(diǎn)子上?是Andrew Koenig的書寫得不夠好?說了誰也不會(huì)相信。因?yàn)閷?shí)際上,這里的原因根本不是技術(shù)上的,而是非技術(shù)的。
眾所周知的一個(gè)事實(shí)是,從最表層講,C++的最嚴(yán)重問題是在語言學(xué)習(xí)階段占用了學(xué)習(xí)者的太多時(shí)間。翻一翻你的C++書架或者電子書目錄,絕大多數(shù)的C++“經(jīng)典”都是在講語言。在我們通常的意義上,要“入門”C++,在語言上需要耗的時(shí)間一般要兩三年。而要“精通”C++,則搞不好需要耗上十年八年的。(這跟Peter Norvig說的“十年學(xué)習(xí)編程”其實(shí)不是一回事,人家那是說一般意義上的編程技能,不是叫你當(dāng)語言律師。)
那為什么我說“C++的復(fù)雜性是根本原因”是個(gè)有漏洞的推理呢?因?yàn)椋屓藗冊谑褂靡婚T語言去做事情之前耗上大量時(shí)間去學(xué)習(xí)語言中各種復(fù)雜性,除了語言本身的復(fù)雜性的事實(shí)之外,還有一個(gè)重要的事實(shí),那就是學(xué)習(xí)者的態(tài)度和(更重要的)方法。而目前大多數(shù)C++學(xué)習(xí)者的態(tài)度和方法是什么呢?——在真正用C++之前看上一摞語言書(日常編程八輩子都未必用得到)。而為什么會(huì)存在這樣的學(xué)習(xí)態(tài)度呢?這就是真正需要解釋的問題。實(shí)際上,有兩方面的原因:
事實(shí)4:市面上的絕大多數(shù)C++書籍(包括很多被人們廣泛稱為“必讀經(jīng)典”的)實(shí)際上都是反面教材。
也就是說,隨便你拿起哪本C++書籍(包括很多被人們廣泛稱為“必讀經(jīng)典”的),那么有很大的可能這本書中的內(nèi)容不是你應(yīng)該學(xué)的,而是你不應(yīng)該學(xué)的。我之所以這么說有兩個(gè)原因,因?yàn)橐?,我曾?jīng)是受害者。二,也是更實(shí)質(zhì)性的原因,這些所謂的必讀經(jīng)典,充斥的是介紹C++中的陷阱和對于C++的缺陷的各種workarounds(好聽一點(diǎn)叫Idioms(慣用法)或techniques(技術(shù)));
又因?yàn)?FONT>C++中的這類陷阱和缺陷實(shí)在數(shù)不勝數(shù),所以就拉出了一個(gè)“長尾”;這類書籍在所有語言中都存在(“C缺陷和陷阱”、“Effective Java”、“Effective C#”等等),然而在C++里面這個(gè)尾巴特別長,導(dǎo)致這類書數(shù)不勝數(shù)。三,這些書中列出來的缺陷和陷阱根本不區(qū)分常見程度,對于一個(gè)用本程序員來說,應(yīng)該希望看到“從最常見的問題到最不常見的問題”這樣的順序來羅列內(nèi)容,然而這些書里面要么全部混在一起,要么按照“資源管理、類設(shè)計(jì)、泛型”這樣的技術(shù)分類來介紹內(nèi)容,這根本毫無幫助(如果我看到一個(gè)章節(jié)的內(nèi)容,我當(dāng)然知道它講的是類設(shè)計(jì)還是資源管理,還用廢話么?),使得一個(gè)學(xué)習(xí)者無法辨別并將最重要的時(shí)間花在最常見的問題之上。
最最關(guān)鍵的是:這些書當(dāng)中介紹的內(nèi)容與成為一個(gè)好程序員根本毫無關(guān)系,它們頂多只能告訴你——嗨,小心跌入這個(gè)陷阱?;蛘吒嬖V你——嗨,你知道當(dāng)你(八輩子都不一定遇到)遇到這個(gè)需求的時(shí)候,可以通過這個(gè)技巧來得以解決嗎?結(jié)果讀了一本又一本之后,你腦袋里除了塞滿了“禁止”、“警戒”、“燈泡”符號(hào)之外,真正的編程素質(zhì)卻是一無長進(jìn)。
又或者有這樣一類書,熱衷于解釋語言實(shí)現(xiàn)背后的機(jī)制,然而語言特性本質(zhì)上是干嘛用的?是用來在實(shí)際編碼中進(jìn)行抽象的(說得好聽一點(diǎn)就是“設(shè)計(jì)”),不是用來告訴你這個(gè)特性是怎么支持的。比如我就見過以下的情景:面試官問:“你知道虛函數(shù)嗎?”得到的回答是一堆關(guān)于虛函數(shù)表機(jī)制的解釋。面試官又問:“那虛函數(shù)的好處是什么呢?”到底為什么要虛函數(shù)呢?得到的回答是:“恩…啊…就是…多態(tài)吧”(這時(shí)已經(jīng)覺得回答不夠深刻了)。再問:“那多態(tài)是干嘛的呢?”啞口無言。