如何從只會 C++ 語法的水平到達完成項目編寫軟體的水平?

學習 C++ 有一段時間了,但只是停留在熟悉語法階段,在看 C++primer,不過感覺這本書比較深奧,不太適合,總想硬著頭皮讀下去(也寫書上的代碼),但效果不佳。在網上看了好多學習 C++ 的路線,有說直接從感興趣的項目入手,本人也在 Github 上找過,不過大多數都看不懂,就更談不上對哪個有興趣了,所以一籌莫展。本人不是科班出身,希望少走彎路,望大神們多多指導,最好分享一下自己的親身經歷,尤其是在最初只了解語法的階段事怎樣一點一點接觸新的知識或者開始做項目的?還有一個問題就是演算法和數據結構應該如何融入到整個 C++ 的學習當中?


其實你從GitHub上找C++項目,那些都是已經成型了的,所以你相當於閱讀一個工程性的代碼了,上面不是談到STL了,我就來做一次簡單的引導吧。

我們首先這樣,先打開cppreference.com網站,然後就會有Strings Library,Containers Library等東西,那麼你就可以按這個目錄來實現,比如Strings Library點擊進去std::basic_string,這個時候會看到很多的函數方法,如構造函數,front,back等,那麼你就需要來想想怎麼實現這個東西。最開始的時候,你甚至都可以不用模板,就從簡單的開始,如剛才提到的構造函數和兩個方法:

class MySTLString
{
public:
MySTLString();
MySTLString(size_type count, char ch);
MySTLString(const char* s);
const char front() const;
const char back() const;
};

這樣你就開頭了,這裡你看,我也只是寫了幾個構造函數和方法而已,其實string還有很多構造函數,但是我們可以先簡單一些,慢慢來。

然後我們就可以來思考實現了,我們閱讀文檔:The class template basic_string stores and manipulates sequences of char-like objects. 可以發現String其實是需要存儲和維護一個sequences of char-like objects,那麼這是什麼呢?sequeces of char-like objects其實不就是char*么?因為char*就是表示這個意思,於是我們需要增加一個這樣的內部成員來表示

class MySTLString
{
public:
MySTLString();
MySTLString(size_type count, char ch);
MySTLString(const char* s);
const char front() const;
const char back() const;
private:
char* data_;
};

那麼這個時候來實現這些東西,比如默認的構造函數,我們查看文檔:1) Default constructor. Constructs empty string (zero size and unspecified capacity),可以發現其實根本就沒有做什麼事情,就是構造一個空的String,那麼對於這樣的操作,而這樣的話,對於char* data_應該怎麼操作呢?其實就是讓它指向""就好了,於是代碼就是:

MySTLString :: MySTLString() : data_(new char[1])
{
*data_ = "";
}

而如果是const char* 呢?查看文檔 : 5) Constructs the string with the contents initialized with a copy of the null-terminated character string pointed to by s. The length of the string is determined by the first null character. The behavior is undefined if s does not point at an array of at least Traits::length(s)+1 elements of CharT.

所以,簡單的來說,就是提取const char* s的內容,構造出string,其string的長度是由第一個null character決定,其實即const char* s的字元串長度,那麼這個長度自然是strlen(s)。那麼有了長度後,我們應該賦予給誰呢?根據上文所述,string存儲與操作著一個char-like object,即我們這裡的data_,所以既然要從const char*構造出string,那麼就需要提取出const char*的內容,然後賦予給data_,長度是strlen(s)。於是,我們的代碼是這樣的:

MySTLString :: MySTLString(const char* s) : data_(new char[strlen(s) + 1])
{
strcpy(data_, s);
}

而這裡需要注意的則是為什麼會有new char[strlen(s) + 1]呢?因為我們是用""來標記字元串結束的,而strlen是沒有包含""。而strcpy的易錯點是第一個參數為target, 第二個參數為src,而記憶方法很簡單,就是你是想要拷貝過去,如等號,那麼你所需要的格式自然是 target = src

這樣我們就踏出了第一步了,接下來我們可以看看front,這個函數其實很簡單:Returns reference to the first character in the string. 所以這樣的話,其實就是返回data_的第一個成員即可,於是實現就是:

const char MySTLString::front() const
{
return data_[0];
}

那麼這個時候呢,我們就可以使用MySTLString進行測試了,即實現一個小功能,就進行測試

#include &
#include "MySTLString.h"
using namespace std;
int main()
{
MySTLString str("Hello");
cout &<&< str.front() &<&< endl; }

這其實不就起頭了么?後面你就可以不斷的填充,實現,重構,一步一步就充實了,所以你看其實也沒有這麼難吧,所以關鍵是要踏出去(&就像談戀愛表白一樣,勇敢的踏出去再說,瞎想這麼多幹啥,被拒也是死的悲壯,成功了那就賺大發了,對不對,騷年?&


不要一開始就去看leveldb乃至v8之類的項目,或者抱著一堆書一本本地刷。

版本控制、測試調試、設計模式。。這些是在寫程序的過程中學會的,但是要有意識地去學。語法、語言特性也可以在練習、遇坑、總結中加深理解,沒有嚴格的先序關係。

推薦一些供練手的項目:

1. 基礎(1000行以下?)

實現String/Math等類

實現容器類

序列化/反序列化庫

JSON/XML/..解析

貪吃蛇/俄羅斯方塊(命令行)

幾個機器學習分類演算法。。

2. 小型

貪吃蛇(GUI)並帶AI

Markdown編輯器

正則引擎

代碼風格檢查工具(簡單的分析就行)

單元測試工具

Redis Client

小型HTTP Server

3. 中型

實現Lua解釋器

移植Memcached/Redis

代碼編輯器

Reactor框架,乃至網路編程框架

具體選擇做什麼根據自己的興趣、需求。各人都有所側重,遊戲、語言、網路、系統、機器學習。。

代碼風格與規範

  • 參考Google C++ Style,除了看文檔外可以直接從Google開源項目中學習;

  • 充分利用編譯器,至少要0 warning;

  • 用cpplint,cppchecker等工具檢查


謝邀

首先,如果不是科班出身,第一門語言非常不建議學C++。特別是按你所說,如果處在「只了解語法」的階段的話,強烈建議切換到Java/C#/Python/Ruby之類簡單的語言去。切過去的好處是從功能上而言,你依然可以寫完全一樣的語言;而那些系統細節,你完全可以等到以後對語法掌握精熟之後,真正能用到的時候,再回來補。

至於如何開自己的項目,我同樣認為這是個偽命題。須知在實際工作中,讓你一個人全權負責開一個新項目是非常少見的事情(而且從公司的風險控制角度,這種事情一般也是風險極大,需要避免的事情)。再者,現在的公司都在轉敏捷開發,所以「直接悶頭做一個大項目做完拿出來」這種情況也會越來越少。

相反的,大多數情況下,項目都是從最小的架子開始一點一點搭起來的。所謂「羅馬不是一天建成的」。

關於所謂「自己的項目」,給你的建議同樣是這個路線:

  1. 選擇一個簡單但是有擴充性的方向——比如,做一個windows桌面程序,一個手機app,一個網頁,等等
  2. 從最簡單的方式開始。比如對Windows程序是「啟動後出現一個空白窗口」,手機app是「啟動後出現白屏,可以退出且過程中不報錯」,網頁是「可以顯示出最簡單的index頁面」,等等。
  3. 然後,一步一步往上加東西。比如「把兩個控制項的顯示內容聯繫起來」,「讀取一個文件的內容並全部顯示」,「顯示硬碟上的一個圖片」,等等等等……盡量把你所追加的每個小任務都縮小到兩三個小時可以解決的範圍內。

聽起來很沒創造力?但需知千里之行始於足下。一百個1加在一起一樣能夠有100,但一上來就朝著100努力的話很可能會因為中間的挫折導致你放棄。(心理學來說,人都傾向於去做能不斷得到正反饋的事情,而堅持很長時間才能得到反饋的話很多人就會放棄了。這不是軟弱,這是人性。)

至於GitHub?初學的時候我覺得你根本就不應該參與上邊的項目——只有到了你看別人代碼已經像看小說一樣簡單的時候,參與進去才有價值。否則就像讓一個小學生強行去學微積分一樣,雖然不是說不可能(世界上總有天才),可是過程中付出的辛勞和收穫完全不成正比。倒是還不如讓他把數學按部就班的學上來。到了他有了高中數學基礎的時候,學那些東西就不會那麼痛苦了。

學編程沒有捷徑,但同時也決不是光靠「吃苦」和「拼」就可以解決的。加油。


我的編程基礎:大一暑假修過幾星期的C;大三修C++。目前達成:寫了一些App。

我可能是所有回答者中最low最小白的一個了。

---------------------------------

上過的幾門編程課期末都喜歡用大作業來考核,就是學生自己提交項目,寫文檔,在最後一周找老師答辯,拿分。

學C的時候,大家寫的是命令行版的圍棋打譜程序,24點求解器。學C++的時候,班上有同學做了選課系統,還有不少同學另外學了MFC或者OpenGL,做了貪吃蛇啊學習記錄啊網路學堂啊等帶界面的東西。

如果你覺得「帶界面的貪吃蛇」是一個項目/軟體的話,那這一步還是比較好完成的:

* 確定好項目需求後,查查是否需要自己目前還沒學過的內容,如果有,就學,學好之後想好該怎麼實現,之後往上面砌磚,檢查即可。就像完成一連串的課後作業一樣。

不得不說,以現在的網路發達程度之高,以及我們目前遇到的問題之低級,真的很難遇到解決不了的bug了。不過說實話,在做完上述大作業過程中所費的心力,真的是比刷完一本書的習題還要多。

吶,寫完了這個,就會有種」啊其實我好像能做很多事情「的奇怪的成就感呢。

然後我就扔掉程序書愉快地玩別的去了。

--------------------------------------------------------

後來有一天,我在做平板支撐的時候,非常非常希望有一個一鍵倒計時,字巨大,且結束後能叮一聲的秒錶。但是應用商店裡沒有人滿足我這個傻爆了的需求。

於是我就重新安了個VS,申請了個開發者賬號,寫了個秒錶,然後就自己用了。

好吧,詳細過程其實是這樣的:

1. 查了查做界面需要什麼語言;

2. 然後學了怎麼做文本塊等我的秒錶中用得到的東西,把界面做好了;

3. 然後想想該怎麼實現」摁了下去就開始變數字「的效果,查了查有哪些現成的計時的類/函數可用,又查了查怎麼播放「叮」,就寫完了。

從開始寫,到寫完,大概用了一個晚上。然後把這個事情告訴了室友及幾個同學,就沒了。

結果過了一星期竟然有好多不認識的人下載了這個App!驚呆了。

當有了一撥人告訴你」這個地方有問題「的時候,真的會產生出一種奇怪的責任感,督促著自己去改掉程序中不合理的地方,讓你每天都會惦記著,要把代碼變得比昨天更好一些。

再往後,越寫,就越知道自己是多麼欠缺,於是就開始有針對性地學習和訓練自己。比如要學習如何調用感測器,就寫了個小小的羅盤app;比如要學習json,就寫了個色卡展示app……

我覺得目前這一步,和我「只會C++語法」的階段,其實差不太遠。真要說差些什麼,都是些具體實現細節上的小trick而已:

* 在剛剛學完書本的時候,我遇到bug往往會去扒書;現在,我遇到bug會先看看報錯信息想一想,想不出來就stackoverflow;

* 在剛剛學完書本的時候,我想用到新的函數/類的時候往往還是去扒書,必須看懂了好幾頁的講解和例子之後才敢動手;現在,我會翻MSDN,對著描述試出來;

* 在剛剛學完書本的時候,我在想新做一件事情的時候會查需要學習哪些基礎知識,然後借書把所有東西學到差不多為止;現在,我會在自己能力範圍內先做一做,然後再去刷書,直到實現為止;

* 在剛剛學完書本的時候,我常常因為無意間改崩了代碼並且還改不回去而心情沮喪;現在,我知道了用github來拯救生命,以及應對用戶「加功能」的要求;

* 在剛剛學完書本的時候,我覺得學完了書就可以自豪地在簡歷上加一句「掌握C++」了;現在,我覺得其實掌握語法其實並不那麼值得自豪,但是很重要:只掌握語法我好像什麼都做不了,但掌握了語法,就是掌握了通往了這片天地的鑰匙,它允許你在其中走路、奔跑、打滾,嘗試著做非常酷的事情。

嘛,既然你已經進入了這片天地,不妨從走路開始,一點點地嘗試著做更棒的事吧~


C++不僅是一門語言,C++是一系列library、 toolchain、framework、 設計模式 、系統API 、調試技巧的集合。

只是工程師說的時候只說自己是做C++的,因為總不能把以上這些都念一遍,因此導致外行有些誤會以為學了語法就夠了。

學會基本語法只是相當於學會26個字母,離寫出小說差得遠呢,雖然看起來小說上都是26個字母,但真的差得遠。

相當作家也要從寫一篇作文開始,嘗試下寫個小app吧,計算器,五子棋,http下載器,網路聊天工具等等。


個人學習體驗,可以按照C++的幾個範式進行針對訓練。

比如模板的使用可以寫模板vector string stack queue BinarySearchTree hashtable 等等,順便鞏固數據結構。

OO的部分可以學學Qt,寫個文本編輯器,俄羅斯方塊,音樂播放器之類的(Qt demo裡面都有,不僅有代碼還有教程)。

或者模仿大神的工作,寫個編譯器前端(上手有困難的話推薦藍色大大博客關於詞法分析的部分),順便提高對編程語言認識的層次。

C的部分練習可以試試OS方面的實驗或者socket編程。或者寫寫圖論演算法之類的。

練完僅僅是比較熟悉了,距離掌握C++還差一點境界。

中間遇到問題應該從effective系列中汲取營養。

有所追求的看看深入理解對象模型,會加深對C++的理解。

我自己感覺有很大幫助的是入門時候寫的模板數據結構、後面寫的表達式求值,以及詞法語法分析器。


題主你聽我說,你眼中「比較深奧」的 C++ Primer,只是一本很粗淺的入門書而已。C++ 這種複雜度高到爆炸的語言,不認真讀幾(十)本大部頭,是很難寫出靠譜的代碼的,具體請參考以下這個書單:c++ faq - The Definitive C++ Book Guide and List。

講真,既然你是非科班出身,我覺得你能在大三之前把 C++ Primer 認真讀完就已經很不錯了,畢竟在華南某理工大學的大四准死程中,認真讀完這本書的還是少數(對不起我校太弱了不能當作典型

不過以 C++ 為主要工作語言的人還是佔少數,大部分人還是去搞安德猴、iOS、Java 大法、PHP 大法什麼了。所以,題主你為什麼不去選擇一個輕鬆一點的語言來入門呢?比如 Haskell、Rust、Python 什麼的,或者 Java、JavaScript、PHP、Go 什麼的也可以啊(


學編程從會語法到能做項目之前,起碼還要掌握:

1. 一些常用的、非標準庫的API。比如C++,目前C++14的標準庫仍然沒有網路通信或者GUI相關的模塊,學一下Boost和Qt還是有必要的。其他語言同理。

2. 每門語言都會自發形成一些idiom和design patterns,小到變數名怎麼取、縮進怎麼弄,大到模塊怎麼組織、哪些語言特性慎用或勿用。

3. 使用調試器;用profile指導優化;寫測試,用測試作為重構時的保障。

4. 至少掌握一種VCS(比如git)

5. 掌握這門語言的編譯工具鏈。C++應該熟悉編譯器的pipeline,了解鏈接過程,會寫Makefile,編譯動態/靜態庫,分析core dump文件,用gcov測試code coverage等。。(感謝 @Coding Program 補充)

等等。。歡迎補充。


嗯?不是說《C++ Primer》是一本入門向的C++參考書嗎……卧槽難道我被坑了?

我看了幾章,感覺挺適合我的,裡面的一些tip、note還有warning的確戳到了我的一些點上。無論如何我會把它看完。也建議題主不要放棄。(課後作業要動手敲)

另外,熟悉語法已經很不錯啦。但除了語法,建議題主熟悉熟悉標準庫,畢竟實際項目中最常用的就是這些標準庫了。


1. 上知乎,關注C++

2. 閱讀問題,留意大牛回答問題時所使用的你聽不懂的碉堡專業名詞,把它們記下來。

3. 在wiki上搜索這個概念並理解它的用處。

4. 在自己的項目中試圖使用它。

5. 遇到問題後,就查閱MSDN、cpprefrence、API文檔等了解這些概念的具體實現。

6. 多使用幾次熟練一下。

7. 回到1循環。

警告:對C++採用此學習模式可能導致嚴重的不適和副作用,智商不夠人士切勿模仿。


多寫吧,萬事開頭難,一開始做練習都會多生些挫折,這是必然的階段。


接私活是學習編程最快的途徑,又有錢掙,還能學各種技術,解決別人提的各種神奇的需求。


如果C++ primer都還太深奧的話…再讀一遍吧喵…否則C++門檻都沒摸到喵…

輔助課程:操作系統、編譯原理、線性代數、彙編、C都可以有助於理解C++本身喵~


自己造輪子,比如stl,性能差沒關係,寫得傻逼沒關係,但一定要自己寫。

不會寫就去百度,去google,去問別人。這樣知識水平長進很快。


既然你已經學會語法了,現在可以看點庫相關的東西比如 「STL 源碼剖析」 「Modern CPP Design」等等


以個人的學習經驗和學習歷程來說,碼農對一門語言而言一般會經歷如下幾個階段:

1.寫出非常著名的hello world

2.解出出書後練習題前幾題,之所以是前幾題是因為要麼後面的太難要麼沒耐心看了

3.能獨立完成大作業(比如某某管理系統)

4.能用該語言寫一些簡單的東西去參加比賽

5.能自己造一些(也許沒什麼用的)輪子

6.進入商業性質的項目


不打算搞編譯器、基礎庫、IDE開發工具、大型GUI的人(對,就是輪子們),沒有必要在剛開始學習的時候,過多地學習C++的高級特性(注意,是過多,沒說基礎知識不需要)。

C++並不是人類唯一的高逼格語言,它有很多爹和很多媽和很多兄弟姊妹表哥堂妹等,總體來說,C++和它的高風亮節型親屬親戚們的存在意義在於:更好地實現面向對象編程方法、更好地實現各類模式編程。掌握了面向對象和模式思想和方法,其實你用彙編寫也很容易實現這些高級特性(只是碼字的字數略多一些)。

舉個兩個栗子:1,各大醫院裡用到的高檔核磁共振或X光CT或高解析度的超聲波診斷系統,PC端的軟體,搞不好是Visual Basic 4.0或更早的版本寫的,一直穩定運行到現在(好的MRI都是8位數RMB,CT也差不多)。2,IBM的大型機(MRI你牛,這個傢伙價格差不多9位數RMB起步哇,哦,還沒算10萬個核的超算呢)里還運行著大量80年代編寫的COBOL代碼(阿門,COBOL大神能否給我的卡里多加幾個零?)。

這兩個栗子的意思是說:對一個有價值的產品、系統,除了語言、數據結構、基礎計算機演算法等基礎知識,還包含了眾多的專業知識。

上面的兩個例子中包含的專業知識是:各類複雜的圖像圖形和信號處理演算法,以及,不斷演進的金融系統流程和各種金融監管法規的實現。

現在搞中高端醫療器械,基本招聘要求是數學極佳的博士碼農,當然,數學極佳的煙酒僧偶爾也會成為漏網之魚鑽進去給一點點機會讓你整理一下文檔、做做測試什麼的。

猜想一下過去的幾十年,不同國家不同金融系統落實到不同金融公司的流程已經變化了多少次?各國監管法規也變更了多少次?發現模式設計的重要性沒?十年內同一套基礎核心業務和輔助業務軟體,需要面對888,888次變更!發現面向對象的重要性沒?如果能把這888,888種變更,整理成有關係的88,888種,這將會是多麼幸福的事情。架構之初不考慮這類變態的變化,請100萬個碼農都沒用銀行家+500強CFO包養的碼農其實早已遠遠超過這個數目,土豪碼農握個手,真是一對好機油》。當然對金融軟體系統而言,線性代數、線性規劃、離散數學、邏輯代數、關係數學、統計學、拓撲學、圖論、體系結構、OS原理、網路、密碼演算法和安全體系、資料庫、分散式系統、完備的可靠性和測試理論及方法《這個搞不好,某次太陽黑子爆發可能會把俺的存摺全部清零,當然也可能多加了一百幾十億美刀進去,不同產地的大理石地板也有類似的功效。阿門,呆會去關帝廟燒支香、各種層次的優化演算法、結構層面、直接操作內核存儲器、我司親手設計優化的網卡晶元和資料庫,往指令集添加密碼演算法指令等方法優化之後,再用彙編優化一下跑分幹掉SYBASE、SQLSERVER這些傻鳥,多爽的事等也是必備技能等。

但願題主沒被這段寫的金融軟體碼農的要求嚇倒,傳說中阿三哥在班加羅爾隨便找個高中生培訓兩個星期就能搞到高盛瑞銀的外包業務,為毛突然有人說出的東西如此不同?對不起,我也不知道。

GITHUB、SF上的源碼題主看不懂,大部分情況下,不是因為題主的C++知識缺乏,而是題主還沒開始去學習其它專業知識。具備了這些專業知識,不斷地擼代碼玩的時候,碰到不懂的語言語法問題,再翻書問人也不晚啊。

寫著寫著,發覺俺蠻有寫小說的天分的╮(╯_╰)╭


別聽他們扯淡,看那麼一堆書,你永遠不會寫代碼.

告訴你,準備VS60 編譯器(速度快,方便).也可以用VS。代碼提示好不過編譯器複雜怕你浪費時間在編譯器上。

1.

目標:計算器。

功能:三個編輯框,一個計算按鈕。 在前兩個編輯框輸入數字,按計算按鈕時第三個編輯框輸出結果。

2.

目標:升級版計算器。可以參考,Windows自帶的計算器。

3.

目標:記事本

功能.有打開TXT,保存為TXT,等功能。說白了其實就是RichEdit.

4.

目標:升級版記事本。

功能:更多功能自己去研究。

記住 不懂的百度!百度!百度!等你完成4個目標,恭喜你,你可以開始做一些小項目了。

想當年16歲用VB寫了個記事本,還發到了黑客基地上。雖然很垃圾的一個東西,但是回憶起來很開心。


瘋狂寫Qt。


github。

明路只此一條。

--

真羨慕你們學c++的時候能上網。


推薦閱讀:

這段c++代碼存在內存泄露的可能嗎?
如何格式化代碼能夠將類成員/函數的名字對齊?
請問這個程序為什麼會死在18,19行?
應該如何熟悉GNU工具鏈?例如GCC/Makefile/GDB
C++ 編程軟體有哪些推薦?有沒有比 vc 6 更好的?

TAG:編程語言 | 編程 | C | 編程學習 |