2016年8月12日 星期五

用輕鬆的方式學習 c++

看完 table 1. 的書單, 並不覺得很厲害, 反而覺得這書單會嚇到不少想學 c++ 的人, 甚至為 c++ 招來罵名; 而或者你是那些少數份子, 已經把這些書都讀完而引以為豪。

如果你看完這些書單, 有寫出什麼有趣的程式嗎? 若是沒有, 不是你不用功, 而是這些書單耗掉你太多時間了。

你也會懷疑有輕鬆的方式學習 c++ 嗎?

絕對有!

以下是 c++ 受害者才能寫得出來的文章
要是先看到劉未鵬的文章, 我就不會寫這篇了, 我和他有類似的想法, 但我的文筆和他差太多了, 無法把我想表達的觀點寫的很清楚, 不過寫了就寫了。

我和劉未鵬文章的共同想法: 不想在 c++ 語言細節/特性的地方打轉, 一直注意語言細節/特性, 很容易鑽進去這個地方, 不容易逃出來, 我前陣子就鑽進 template, 好不容易才逃出。或是 overloaded function 怎麼決定採用哪個 function, c++ primer 寫的很清楚, 那些規則很煩人, 但你需要去看這些嗎? 不, 一開始不會有這需要, 一開始的你絕對不會寫成這麼複雜, 讓自己踩到陷阱, 頂多是 print(int), print(char) 這種簡單的用法。

我想用 c++ 寫點有趣的東西, 例如 os kernel, 還沒完成, 目前只建好目錄 (這可容易多了), simple_os 是用 c 實作, 不能用 c++ 實作一直是我的遺憾; 用 c++ 寫的實作品有作業系統之前的 scheme, 和作業系統之前的 c++ library, simple_gui。我覺得這些都比去學習 c++ 語言細節有趣多了。而且用到的 c++ 特性/語言細節很少, 這也是我受害之後才有的想法。

我也不想再看什麼條款的書, 好像一個不注意, 又要落到 c++ 陷阱中了。不是書籍內容不好, 相反的, table 1. 介紹的書本本都是大作, 但我想把注意力集中在用 c++ 寫出我想寫的程式。


table 1. C++ 經典書籍

作者: gocpp (cpp) 看板: C_and_CPP
標題: [心得] 
時間: Sat Aug  6 18:48:53 2005

一些書單, 有一部份沒有繁體譯本。

首先, 關於入門書方面, 我覺得到現在我都沒有看到一部適合初學者的 C++ 入門書。
經典的書都是高手們寫的, 但根本不適合初學者看。這大概是 C++ 族群增長的一大瓶頸。

我個人覺得最適合入門的一本書是 K&R 的那本 C 語言經典, 講解和舉例都非常有水準。
C++ 的話則是「從 C 到 C++ 物件導向革命」。它是 1990 年的書, 作者陳建維先生是當時
C++ 標準委員會的一員。這本書我覺得相當不錯, 用不是很大的篇幅, 從軟體工程,
OO 的思想、觀念, 到 C++ 語言。甚至當時書的附錄就已經提到 template 了。

可惜, 這本書, 現在已經找不到了。這是我第一本看的 C++ 的書。當時這本書和 C++ Primer,
The C++ Programming Language 並稱三大經典。

《C++ Primer》3/e
這本是我最喜愛的 C++ 經典之一。可以說是經典中的經典。現在出到四版,
中譯本年底應該會出來。我看的是第三版, 由 jjhou 譯的。當然,
雖然它叫 Primer, 但絕對不適合初學者。尤其許多細節之繁復 (像什麼名稱決議過程),
保証讓初學者吐血, 我相信連許多老手都會覺得受不了。

基本上我把這本書當作「字典」、「百科全書」類來看, 每當一些細節不是很確定,
就翻翻它。有時晚上無聊抱著它, 不知不覺睡著了。

這本書如果能夠大致流覽過, 並且熟悉其中 60~70% 以上, 我相信已經達到普通
C++ 高手的程度了。

當然, C++ 高手不等於軟體高手。成為編程高手不難, 成為設計高手才難。C++ 其實可以只花很短
(半年至一年) 的時間就精通, 但許多編程、軟體設計經驗的累積, 那絕不是三、五年的事,
通常都得十年八年以上。

《The C++ Programming Language》
C++ 之父, B.S. 的大作。這本書我讀的是特別版。感覺上它比 C++ Primer
更不適合初學者。尤其是連程序設計都還搞不清楚的新手。
這本書的思想、哲學意味很濃厚, 很多篇幅內容不是在講語言的技術, 
而是在講設計的思維。如果看過 C++ Primer, 再來看這本, 應該會有比較多的體悟。

內容方面, 雖然不若 C++ Primer 鉅細靡遺, 但很精致、簡潔扼要, 
它不斷拋出各種「設計」層次(而不是語法)的議題, 沖擊讀者的思考,
迫使你去關注更多編程的本質。

有些部份, 我覺得 The C++ Programming Language 比 C++ Primer 好,
例如許多語言特征為何存在﹖其應用時機, 它給的範例都很適當, 
C++ Primer 則比較注重語法和規則的完整詮譯(畢竟大師是搞 Compiler 的專家)

《Effective C++》
這本書也是經典的經典, 我推薦所有學過 C++, 但自覺對 C++ 一知半解的人, 從這本書開始「重新入門」。

它把 C++ 程序員最常犯的一些錯誤, 不好的用法, 忽略的重要細節, 
用 50 個條款, 分門別類地一一列出。雖然這些內容, 在 C++ Primer
或其他大部頭的經典著作, 都不是沒有寫到。但大概很難有人有耐心從頭到尾看完。
(我猜作者自己也看不下去 ... )

這本書的好處就是, 一次一個主題, 把為什麼要這樣, 來龍去脈, 各種其他舊方法的缺點, 不足之處, 
一一分析出來。讓讀者確確實實了解並掌握優良的 C++ 編程風格的技術關鍵。

如果 C++ Primer 看不下去的話, 可以先從這本開始, 遇到語法細節搞不清楚的時候, 
再去翻查 C++ Primer 等教科書。

《More Effective C++》
同上, 更深入的主題, 某些議題已經可以算是 C++ 高手的程度了
(也脫離教科書的範圍), 例如 Lazy Evaluation, Virtualizing Constructors,
Reference Counting, Proxy Classes ... 等, 有些是特殊技術, 
有些已經算是 Design Patterns 的東西。

這本書當然完全不適合入門者, 它適合對 C++ 各種基本特徵已經很熟悉的讀者看。

《Exceptional C++》
我第一次看這本書時, 幾乎懷疑我是否學過 C++。但是現在, 我只能說, 這本也是經典中的經典。
它已經深入到接觸 C++ Object Model 的層次。特別是 Exception-Safety 這一章一系列的步步深入,
很大程度上改變了我對 C++ 的認識。此外, 它有提到 Pimpl Idiom, 這對改善 C++
編譯效率也有一定的幫助。其他的主題, 例如泛型編程和對標準庫的幾個討論議題、暫時物件、
物件壽命、自動轉換 ... 等, 也頗有深度。如果沒看過這本, 且對自己的 C++ 功力頗有信心的人,
可以測試看看。

《Inside The C++ Object Model》
這本書和《Essential COM》, 是我讀不太下去的兩本書。僅供高手們參考。適合有志深入 C++ 語言核心
(例如想要發展 C++ Compiler 的人)鑽研。其實它並不是很難, 但我認為實用性不高, 有時間, 
不如看看 Effective/Exceptional C++ 系列。

《The C++ Standard Library》
經典中的經典, 學 C++ 不學標準庫, 就像有腦子卻沒手腳, 難以施展。
C++ 標準庫和大型的 J2EE, .NET 等框架相比, 算是很陽春的。
C++ 標準庫只規範了標準 I/O , 資料流, 異常, 演算法和資料結構, 
還有一些國際化議題。一些重要的功能, 如: IPC, GUI 等等, 都不在其內。

這本書是德國人寫的, 內容務實中肯, 獲得世界一致好評。書中前面有一章特別介紹 C++
泛型編程基礎, 講得很清楚, 是我看過最好的入門書(學習 STL)、兼工具書、參考書。雖然很大本,
但絕對值得買一本。

《C++ Templates》
這本書好像是 2001 年出的, 中譯本在台灣直到去年才出來。內容完全針對 template
所有的技術細節及應用, 豐富得叫人難以想像。

有時候, 我覺得 template 一直玩下去, 會走火入魔, 這本書的內容,
某些時候給我這種想法。不過還是值得一看。

《Modern C++ Design》
這本書是近兩年我最愛的一本 C++ 的書, 我簡直愛死它了﹗作者把 C++ template 的編程技術,
推向一個嶄新的世界, 讓許多 C++ 大師級人物, 都目瞪口呆的一本書﹗巧妙地結合 GP 和 OO,
讓動態多型和靜態多型完美地合作無間, 也讓 Design Patterns 領域, 有了全新的視野和思維。
它的實作品, Loki 函式庫也是我常常運用到的 (雖然只有部份能通過編譯, 正常的工作)。

一本有志成為 C++ 高手絕對不可錯過的書。當然, 在此之前, 要先把 C++ Primer 等先學好再說。

《The Design and Evolution of C++》(D&E)
這本書台灣沒有譯, 我起初看的是英文版, 後來知道北京有譯這本書, 就托同事的朋友買回來。

這本書不適合學習, 適合對 C++ 發展歷程有興趣的人看 C++ 之父現身說法, 親自講述,
C++ 是根據哪些原則原理產生的它的各種語言特徵, 取舍之間, 又經過了什麼特殊考量。
此外, 有些歷史因素, 影響 C++ 的發展, 裡面都有提到。

我當作小說在看的一本。

《Imperfect C++》
算是比較新的一本書, 台灣沒有譯這本。內容討論到一些比較細部的問題。適合對 C++ 有深入了解的人。

此外, 《More Exceptional C++》和《C++ Gotchas》這兩本不知為何, 
我覺得不太喜歡, 雖然它討論的議題都很深入。或許實用性不高的關係, 
我老是覺得它似乎有點 C++ 學究的味道。

不過, 這兩本也是公認的經典。

還有很多其他的, 例如《Thinking in C++》或《C++ 沉思錄》, 也都是經典, 前者也不錯,
蠻適合當參考書用 (後者比較像故事書)。但以學習 C++ 而言, 我認為《C++ Primer》,
《The C++ Programmin Language》這兩本比較適合(兼具教科書和參考書的價值)。

《Essential C++》這本, 評價不高, 它既不如 C++ Primer 完整, 也不適合初學者, 
只能說是聊備一格。應該不用看。

另外, 專講 STL 的書也很多, 有的也很深入, 但從實用的角度, 我認為只要一本
《The C++ Standard Library》就大致足夠了。
另外, 《Effective STL》也是一本很不錯的書, 可以糾正很多不好的用法。

其實對其他語言的使用者而言, 很難接受學個 C++ 要看這麼多書 
(我想也只有 C++ 的熱愛者, 才會真的去讀這些書)。

C++ 要實用, 還要學習許多 GUI, Database, IPC 等等的 Framework, 
這些東西沒有統一標準, 可說憑個人的選擇, 通常是基於工作環境的需要。

從 C 到 C++ 物件導向革命 - 抄襲的作品
學習 c++ 一定要這麼辛苦嗎? table 1 提到的書單我幾乎都有 (中文版本)。我反而推薦《Essential C++》, 不過這是給有程式經驗的人看的, 並不是給程式語言初學者, 薄薄一本, 也不會提到完整的 c++ 特性, 看完就可以使用 c++ 來寫程式了。

「從 C 到 C++ 物件導向革命」這本書雖然不錯, 我也有, 但這是抄襲的作品, 請看作者自己的發文。《Chris Chen (陳建維) 對於「從 C 到 C++ 物件導向革命」的說明

我不是來贊同書單的, 相反的, 我是來減少書單的, 畢竟看的書要是多了, 誰也不相信能學的輕鬆。

我把 c++ 分為兩種使用者:
  1. c++ 使用者
  2. c++ 底層開發人員
這麼直覺, 應該不用解釋了。

而到了 2016 年, 至少又要加上幾本書了。第四版的 the c++ programming language, 第五版的 c++ primer, 這兩本這麼厚, 吃的下的人不多, 到不是因為看不完, 而是會排擠學習其他知識的時間。真要挑一本看, 當然是看 Bjarne 的書, 因為我實在想不出不看 c++ 發明者寫的書而非要去看其他人寫的理由。

Effective C++, More Effective C++, 看著手邊的 effective modern c++, 未來再看到 more effective modern c++ 我應該也不會意外。拿到書後沒有急著看 effective modern c++, 我的心境已經和之前不同了, 當初 Effective C++, More Effective C++ 看的津津樂道, 不過對於 c++ 的掌握沒什麼幫助, 不是書不好, 而是我忘光了書中內容了, 而這 3 本薄薄的, 不會花上太多時間。

你不想在語言上花太多時間吧! 只有 c++ 本身並不能寫出什麼有趣的程式, 我好像打自己臉了, fig 1 就是用 cout 畫出整個畫面, 但其實也沒那麼簡單, 如果只有 c++ 本身的知識, 也是做不到的。fig 1 是一個很有趣的程式。

難道你很喜歡演算法那些題目嗎? 什麼反轉二元樹, linked list, graph 演算法, 二元搜尋樹, 河內塔 ... 那你是個例外。通常把某個平台的 api 組合起來的程式才是我們更常見的程式。

像這個看起來很簡單的《文字大富翁》只有 c++ 本身的知識, 是完全寫不出來的, 光是畫面的繪製就難倒你, 寫出這樣的程式有沒更吸引你呢?

使用 c++ 本身甚至連抓取特殊按鍵 (F1, Pause 之類的) 都有問題, 我們更常會需要類似的功能, 所以還得知道怎麼辦到這件事情, 想寫視窗程式吧, 還得學習 qt, 想寫手機 app, 還是可以學 qt, 想寫網路程式還得學 socket, 想在 linux 上寫程式, 得花時間看 apue, 想寫 windows 系統程式, 還得看大奧祕之類的書, 想寫 compiler/interpreter, 得找編譯器的書來看, 想寫 os, 得找 os 相關的資料, 想寫網頁程式, 那你挑錯語言了, c++ 會讓你很累。除了語言本身還有想寫的領域知識得學習, 把時間花在語言本身不是太划算。

劉未鵬寫文章的時候應該還沒有這本 -《C++程式設計原理與實務-第二版》, 這是 Bjarne 寫給初學者看的, 強力推薦。

fig 1. 使用 cout 來繪出畫面

再來本《c++ 標準庫》, 我知道有免費的英文網站可以查, 但中文是這本書的最大價值, 你懂的, 如果你要靠免費的英文網站學英文又學 c++, 那你挑錯教材了, 很有可能落得兩頭空, 既沒有學好 c++ 標準程式庫, 英文也沒有進步, 一心二用是很困難的, 連 Don Knuth 一次都只做一件事情, 我們平凡人就更無法同時做兩件事情了。

接著該讀哪本呢? the c++ programming language the 4th 中文本, 現在的我會選這 3 本書來學習 c++, c++ primer 就不讀了, the c++ programming language 應該可以覆蓋 c++ primer 內容, 我會讀 c++ primer, 完全是因為侯捷的翻譯, 如果不是侯捷翻的, 我只會去看 the c++ programming language, 看聖經版就夠了。但這本不是馬上看, 而是用 c++ 寫了不少程式後, 再來翻閱, 所以實際上只要讀 2 本, 甚至也不一定要讀 c++ 標準庫, 那更是只要讀一本, 到了這時候應該不會滿足《C++ 程式設計原理與實務》裡頭的東西, 會想要再知道多一點, 就靠它了。
  1. C++程式設計原理與實務-第二版
  2. c++ 標準庫
  3. the c++ programming language the 4th 中文本

我認為這樣就足夠當個 c++ 使用者, 其他的就隨緣了。如果還要讀書呢? 那就再把 1, 3 拿出來讀, 正常的人應該把讀過的內容都忘光了。再來的話你應該有能力選要看的 c++ 書籍, 可以從各地的推薦書單找到自己要的。

若你要像我一樣把 c++ 用在作業系統之前的程式上, 那所需要的知識大部份就和 c++ 無關了, 可以從我的 blog 文章得知個大概。這是《系統底層開發人員》的領域, 不是《c++ 底層開發人員》, 也許有人會同時有這兩種屬性 (ex: Bjarne Stroustrup), 不過這兩樣是不同的, 我用 c 或其他語言也可以辦到這件事情, 和 c++ 無關, 用 c++ 做這件事情只是因為我喜歡 c++。

那你說沒學到的其他 c++ 特性怎麼辦, 沒怎麼辦, 不會那些不會嚴重影響到寫不出程式來。c 沒有 lambda, closure, 沒有物件導向, 沒有 template, 沒有很多語言有的豐富特性, 但我需要為你證明 c 的能耐嗎? 但若有些特性不重要, 那麼 linux 裡頭為什麼又用上那麼多的 gnu extension 呢?

語言特性真的令人又愛又恨, 怎麼選擇是智慧的表現。

c++ 最令人注目的 OO, 就是 class 的運用, 以 c++ 使用者來說, 只要使用別人寫好的 class 就足以, 這個層級的學習就簡單很多, 大多是一些 class 語法, 你不需要學習如何寫好一個 class 的 ctor/dtor/assign operator, 只要有概念即可, 大概也不會有機會去寫這些。但是 c++ 底層開發人員就不同了, 他們得知道如何撰寫這些, 除了功能正常, 還得有效率。這部份的學習就辛苦一點, 然後在加上繼承/多型又會再辛苦一點; 再來個 template class, 又再辛苦一些。

呼, 還好我是個 c++ 使用者, lucky。我們需要的大多是 RAII, 這個就比寫完整組的「那三個」容易多了, 頂多寫個 ctor/dtor 複雜度不高, 別小看這個, 光是這樣, 就已經比 c init/destory 好用不少了。overloaded 也是好學的有用特性, 看過就記住了, 但是 ... 搞得太複雜還是會害到自己。

再來就是 c++11, c++11 之後又多了很多折磨人的特性, 有 move semantic, lambda, !@#$%^&*() ... 夠折磨你的, 完了嗎? 還沒, template 的 meta-programming 加上 variadic template 技巧更是令人不知所措, 用別人寫好的很快樂, 自己寫就不好玩了。

但學習 c++11 raw string, 和 range base for loop 語法, 一點也不難, 撿起他們來吧! 如果不想學也沒關係, 使用原本的 for loop 語法也不會讓自己看來像笨蛋, 同樣的, 用 range base for loop 也不會讓自己看來很高竿。move semantic 就不用勉強自己了, 我覺得這個特性不是很容易理解, 我花了不少時間才弄懂, 就當個單純 c++ 使用者。

沒有這些之前, 你 c++ 程式也寫的好好的, 這不會造成程式寫不出來的後遺症, 不是一定要學習的關鍵。用 c++ 98 也不糟糕, 很多人也只用 c++ compiler 而不寫 c++ style 程式。我不是說不學 c++11, c++14, c++17, 而是沒那麼急迫的需要學習他, 當然你若是把自己定義為 c++ 底層開發人員, 那就一定要會的。

最折磨人的 meta-programming 呢? 這個恐怖的 template 技巧, 不會會怎麼樣嗎? 我不知道, 但我發現他並不會阻礙我完成一個程式, 我連語法都看不懂。

你會不會這樣? 花了很多時間學習的 c++ 特性, 一定要想方設法把他派上用場, 好像不這麼做就浪費了好不容易學成的絕招, 這是為用而用, 而不是真的非用不可。我很常看到 c++ template 技巧, 我一個也不會, 但我也放棄治療學習了, 根本看不懂那些角括弧, 當個 c++ 使用者會比較輕鬆。一樣不是不學, 而是把他當成加分的東西, 慢慢來學習。

沒用上 c++ 特異功能, 並不會使你看起來像笨蛋, 掌握 if/else, while, function call, 就已經是很大的武器了。

這樣扣完之後, 大概只要學習和 c 一樣的部份, 加上一點點 class 用法, 再加上標準程式庫, 這樣的負擔相信每個人都負擔的起, 就不會大喊學 c++ 吃不消, 當然由於那可怕的指標以及沒有 gc 加持, 應該還是比學 java 難上一點。哦! 我忘了提到 exception handle, 那個就自己斟酌吧! return error code 也還可以用, 不一定非用 exception handle 不可。

哦! 有些朋友會說我根本是在寫 c, 我不反對 (不過我堅持我用的是 c++), 但我日子很好過, 沒被這些嚇死人的特性搞死。我很常綜合使用 OO 和單純的 class 語法, 哪個寫來順手就用哪個, 以前我也很煩惱要用 OO 還是一般 function, 用 define 還是 const, 連程式都還不知道寫不寫的出來, 就在煩惱這些小事不覺得想太多了嗎? 只要你寫的夠多, 最終就會知道是 define 比較好用還是 const 比較好用, 書上寫那個好的原因, 可能你根本就無法體會, 而一旦你有所體會, 也不用去管書上的建議了。

而混著用很好用, 我就混著用了。

除了這個, c++ 給了你很多個選項, printf, cout 我也常常混著使用, 因為我有時候覺得 printf 好用, 有時候覺得 cout 好用, 我知道這習慣不好, 請不要學我。但 global object ctor 裡頭不能用 cout, 我也只能用 printf(), 沒什麼選擇, 這是中招好幾次之後留下的深刻記憶。

c++11 在 iostream 直接加入了這行:
static ios_base::Init __ioinit;

How can I ensure that global variables are initialized in the correct order?」介紹了 cout 是怎麼辦到的。

解決了 cout, cin 在什麼時候會被初始化的問題, 但我還是不太願意這樣用, 我不想對 cout/cin 有特例之外的處理, 一個原則就好, global object 的初始化是沒有保證的, 不要在 global object ctor 使用 global object, 這住這條原則就夠了。

令人驚豔的 boost 我也沒用過, 綜觀下來, 你應該不會覺得我是 c++ 高手, 我也的確不是 c++ 高手, 很多人都誤會我 c++ 很強 (這是我的平凡之其五), 但我還是用 c++ 寫了讓人覺得還蠻厲害的程式。
  • simple_os - 呃 ... 這不是用 c++ 寫的不算
  • simple_compiler - 目前只是 interpreter, 用到的 c++ 特異功能只有 class, c++ 標準程式庫, range base for, auto 不算特異功能, 但你不會認為這個東西很好寫吧!
  • simple_stdcpplib - 因為寫了容器 (list, vector, map), 我用了 template function/class, 這個 c++ template 真是難死我了。
  • simple_scheme - bj4
  • simple_gui - 我參考了《事件式驅動式程式設計》, 以 MVC (就是現在 web 程式上很熱門的 MVC) 完成了一個文字模式的 window system。

我沒像劉未鵬《我的C++學習歷程(old)》這麼努力學習 c++, 我只有看書, 沒有去看 stl/boost/others 的程式碼, 這是一個學習的敗筆, 幾乎只有學生時期才有這樣的時間, 看別人的程式碼是很好的練習, 因為上班後就知道要改很多前人寫的程式碼, 看懂他們很重要, 好 code 要看, 爛 code 更要看, 要不然你怎麼改得動。別期待能看到好 code, 那是上輩子修來的福氣。而且能在爛 code 上持續加上新功能, 不是也有另外一番成就感嗎?

我的學習過程在《 [嘴炮] - c++ 之電腦語言之爭》描述過, 我花在看書的時間太多了, 不應該這麼做, 應該要把時間花在真的寫程式上, 不管是寫在紙上還是在電腦上, 總之去寫就是了。

simple 系列是我亡羊補牢之作。要是能在學生時代完成這些, 現在寫的就是 complicated 版本了。


紙上得來終覺淺, 絕知此事要躬行。

ref:

C++, Farewell~
https://github.com/kasicass/blog/blob/master/cpp/2018_11_23_farewell_cpp.md

2 則留言:

使用 google 的 reCAPTCHA 驗證碼, 總算可以輕鬆留言了。

我實在受不了 spam 了, 又不想讓大家的眼睛花掉, 只好放棄匿名留言。這是沒辦法中的辦法了。留言的朋友需要有 google 帳號。