很多人把學習C++語言當成學習VC了,我曾經就走過這樣的彎路。當學了很長時間的VC後還是得回過頭來學習C++語言本身。
那麼學習C++從何處入手了?
C++語言相對於C語言來說引入了兩個大的新東西,一個就是物件導向(具體來將就是類),另外就是模板技術(模板編程或者叫泛型程式設計是進來非常流行的技術,在C#中雖然還沒有對泛型程式設計的支援,但是相信在將來也一定會加入這一功能),模板是C++中比較複雜的部分,但是作為一個真正的C++程式員,這部分很重要。尤其是對C++標準程式庫的掌握尤為重要。
剛開始的時候千萬不要直撲VC中的各種嚮導和設計器。因為依賴開發環境產生的很多代碼會把我們搞糊塗,也不利於我們學習C++語言本身。我的建議就是產生一個空的控制台工程,然後自己向裡面添加檔案。
如下就是一個簡單的控制台程式:
//robindy/list.cpp #include <iostream> #include <list> using namespace std; int main() { list<char> coll; for(char c = \'a\'; c <= \'z\'; ++c) { coll.push_back(c); } list::const_iterator pos; for(pos = coll.begin(); pos != coll.end(); ++pos) { cout << *pos << \' \'; } cout << endl; return 0; } |
對using namespace std;的解釋:所謂namespace,是指標識符的各種可見範圍。C++標準程式庫中的所有標識符都被定義於一個名為std的namespace中。
由於namespace的概念,使用C++標準程式庫的任何標識符時,可以有三種選擇:1、直接指定標識符。例如std::ostream而不是ostream.完整語句如下:std::cout << std::hex << 3.4 << std::endl;2、使用using關鍵字。
using std::cout;using std::endl;以上程式可以寫成cout << std::hex << 3.4 << endl;3、最方便的就是使用using namespace std;這樣命名空間std內定義的所有標識符都有效(曝光)。就好像它們被聲明為全域變數一樣。那麼以上語句可以如下寫:cout << hex << 3.4 << endl;
這段程式用到了標準模板庫,在螢幕上列印字元a~z,其中main函數的標記式只有兩種是被C++標準委員會接受的,只有以下兩種寫法是符合C++標準的,是可移植的。即:
int main() { } 和 int main(int argc, char* argv[]) { } |
C++在main()的末尾定義了一個隱式的return 0; 但是在VC中必須顯式的寫出return語句。
在BCB中可以不寫return而編譯通過。
這段程式中用到了STL中的容器:鏈表。先是向鏈表中插入26個字母,然後從遍曆鏈表,輸出字元。
我不建議初學者一開始就從模板庫入手,但是我建議應該逐漸地有意識地學習模板庫。如我們應該熟悉cout和cin的用法(位於iostream),而減少使用老式的C函數庫中printf和sc anf等。
從控制台入手的好處就是避免我們理解VC中嚮導等工具產生的其他代碼,整個程式的流程很清楚。新手學習VC的一大痛點就是搞不清楚整個程式的流程(從那條語句開始執行,然後從那條語句退出。MFC做了太多封裝,掩蓋了事實的真相,^_^)。通過控制台我們可以很快地學習C++語言中的很多新特性。如類的封裝、繼承和多態等。通過這個時期的學習,要能夠掌握三個東西: C++關鍵字、文法(重點是和物件導向有關的,以及模板)、C++標準程式庫(知道怎麼使用即可,要徹底掌握需要很多時間和精力)。至於與介面有關的東東(MFC中很大一部分是與介面相關的類,所以我認為MFC很臃腫而無聊!回頭看過以前用MFC寫的程式,有一種“垃圾”的感覺。)
自己做個測試:寫一個控制台程式,在其中體現出類的繼承,函數重載,動態多態(通過虛函數實現),資料封裝,C++標準庫的運用。
如果你能夠輕鬆搞定,恭喜你,你已經通過C++語言關了。不過C++實在是一個複雜的東東,其中有各種千奇百怪的文法現象,如果沒有三、五年的功力,千萬不要說自己懂C+ +.^_^.推薦書籍《Thinking in C++》(有精力的話,可以直接讀原版)
《Essential C++》
本來我計劃繼續說說如何來進入C++世界的,但是琢磨了一下,覺得還是要先解決一個問題:為什麼要學習C++?我覺得在軟體開發這個行當了裡除了為了生計外,學習新東西都是應該以興趣為導向的。所以撇開我個人對C++的偏愛,我想為你樹立起學習C++的信心和興趣。當初我對自己學習C++的第一個忠告就是:不能半途而廢!起初是興趣驅動,後來則是生計所需,最後還是迴歸到了興趣。畢竟我從中得到了樂趣,這就足夠了。在學一個新東西前,解決動機問題很重要。就如同殺人一樣,如果只是突然興起,那麼等嘗試了以後,是沒有成就感的。革命先烈們為我們作出了很好的榜樣,就算我們在學習C++的道路上遇到了太多困惑和痛苦,但是我們畢竟為自己的信念做了努力,我們知道自己在做什麼,知道自己在追求什麼。
C++適合做什麼樣的開發?
C++是一門廣泛用於工業軟體研發的大型語言。具有很高的複雜性和解決問題的能力。C++不僅在開發上極具價值,同時在學術界也就有很高的價值。有關C++的文章應該可以用浩如煙海來形容了吧。C++的世界級經典書籍也是數不勝數。然而,目前開發語言是如此地繁榮,就連微軟也在推出了新的開發語言C#。一個不可否認的現實是,在低階程式設計領域,C++擠壓著C同時也在承受著C的強烈反彈,前段時間看了據說是微軟作業系統原始碼的東東,其中很多還是C語言。而在高階程式設計領域,Java和C#正在不斷蠶食著C++的地盤。也許Java和C#的狂潮終將迫使C++迴歸本位— 回到它有著根本性優勢的開發領域:低級系統程式設計、進階大規模高效能應用設計、嵌入式程式設計、通用程式設計以及數值科學計算等。果真如此,我認為這未嘗不是一件好事。電力系統軟體所要求的高效能和大規模數值計算正是C++所擅長的。就我所接觸的南瑞和魯能,很多涉及到電力系統計算的軟體如PAS等,都是用C++來開發的。在電力系統軟體開發這塊陣地,C++大有用武之地。C++吸引如此之多的智力投入,以至於這個領域的優秀作品,包括重量級的軟體產品、程式庫以及書籍等,數不勝數。在C++之父Bjarne Stroustrup的個人首頁上,有一頁列出了一些(全部或大部分)使用C++編寫的系統、應用程式和庫。
下面是一些例子(摘自榮耀網站):o Adobe Systems:所有主要應用程式都使用C++開發而成,比如Photoshop & ImageReady、Illustrator和Acrobat等。
·Maya:知道“蜘蛛人”、“指環王”的電腦特技是使用什麼軟體做出來的嗎?沒錯,就是Maya. o Amazon.com:使用C++開發大型電子商務軟體。
·Apple:部分重要“零件”採用C++編寫而成。
·AT&T:美國最大的電訊技術供應商,主要產品採用C++開發。
·Google:Web搜尋引擎採用C++編寫。
·IBM:OS/200. o Microsoft:以下產品主要採用C++(Visual C++)編寫:o Windows XP Windows NT:NT4、2000 Windows 9x:95、98、Me Microsoft Office:Wo rd、Excel、Access、PowerPoint、Outlook Internet Explorer,包括Outlook Express Visual Studio:Visual C++、Visual Basic、Visual FoxPro .NET Framework類庫採用C #編寫,但C#編譯器自身則使用C++編寫而成。Exchange SQL Server FrontPage Project所有遊戲……
·KDE:K Desktop Environment(Linux)。
·Symbian OS:最流行的蜂窩電話OS之一。
很多新手特別容易會對自己所學習的東東產生疑惑、迷茫。覺得自己學這個東西,花了這麼多時間有沒有用,會不會過時?這種思想很普遍。在一些論壇上經常會看到一些各語言的優劣比較,知道自己所學語言的優劣也好,但是如果一味停留在這個層面就沒有用了。
任何語言都只是工具而已。重要的是使用工具的人!就我個人的經驗來講,真正處於業界搞開發的人都願意使用成熟的、為自己所熟知的技術來完成工作。而新手都喜歡用一些比較新的技術來做開發,而且喜歡追求新奇(從介面很容易看出來,花花綠綠的介面多半出自新手)。其實,安於用一些效率可能低下、擴充性和維護性差的方法來解決問題並不是開發人員的錯。他們只是在完成工作而已。但是作為一個真正有上進心的開發人員,我們應該使用更優雅和高效的編程技術,這才是我們逐漸層成編程“大牛”的好習慣。老是停留在原地,很容易被淘汰的。在軟體開發這個行當,尤其如此。無論是對學生,還是一線開發人員,我覺得都不應該產生“書讀夠了”的感歎!我有時候喜歡將以前看過的書翻出來再看,每次總能體會到一些新東西。有關C++語言的書籍更是如此,而且我覺得我所起的題目不是很好。為什嗎?因為我覺得學習語言還只是新手跨入軟體開發“地獄”的第一步,單單學習語言本身是遠遠不夠的,還要學習相關的程式庫(C++當然首選是先學習C++標準程式庫)、相關的平台技術(如。NET),說得更遠一點,還要鍛煉對目標問題的分析、歸納能力等等。工作之前,技術路線自己作主,工作之後,絕大多數程式員將被公司技術路線左右。所以,趁現在還有時間,可以學一些自己感興趣的。如果想搞軟體開發,特別是電力系統軟體的開發,學好C++不會令我們失望。當我們進入C++的前門,然後經過一段黑暗之路,再從後門出來到達光明頂後,我們會體味到“一覽眾山小”的感覺。
推薦書籍:《編程高手箴言》梁肇新(用過超級解霸的都應該知道吧,^_^)寫的第一本書,其中有幾章還是值得一讀的。在這本書中,梁告訴我們,學東西要耐心,要耐得住“寂寞”,走自己的路,讓別人去“說”吧!
最近比較忙,原來打算緊扣主題講講一些具體的C++語言的細節的,但還是抽不出大段的時間了。所以,現在只能再漫談一些關於C++的故事了。
C++源於C語言,還記得很久以前學習C語言的時光(那是一段快樂而充實的時光),可是現在學習C++,並不是在C的基礎上加上了類而已,如果這樣認為,我們是耍不好C++的。因此,C++絕不是C的升級或擴充,我們應該把C++當作一門新語言來學習(C++之父Bjarne Stroustrup語)。
寫程式首先希望是程式能正確執行,其次是效率能夠被接受,再次就是易於維護。C++是一個難學易用的語言。C++提供了太多可選擇的東西,而且使用使用C++來寫程式可以有四種思考模式:基於過程、基於對象、物件導向和泛型。我們使用一種語言來寫程式,並不意味著就是使用語言本身,換句話說,我們更多的時候是使用程式庫在寫程式。比如MFC、STL、ATL、VCL等等。其中要使用C++來寫出結構優美、效能卓越、代碼簡潔、易於維護的代碼,首推C++標準程式庫。STL對效率做了嚴格的要求,而且使用STL寫出來的程式簡潔美觀(前段時間我特意貼了一個要求對若干整數進行排序的文章,其實目的就是用來展示STL的簡潔優雅)。一旦習慣使用泛型思維來考慮問題,我們能夠充分體會到模板帶來的美!
對於數值計算來說,C++標準程式庫可以充分滿足現代化服務和商業計算對資料、資訊的即時回應的要求。
我覺得學好一門語言最重要的就是實踐。也就是多“寫”!“工程經驗之積累”對已具有一段開發時間的程式員而言,非常重要!只有在不斷的積累中,我們才能漸漸體會到C++語言中的一些背後的東西。對於這點,沒有大配量序代碼寫作經驗的菜鳥,也可以藉助《Effective C++》先攢一些經驗值。《Effective C++》是一本好書!。Meyers的書絕對值得一讀,Meyers可以說當今C++社群中數一數二的技術專家。
以下文字應該是去年所塗鴉而成,主要是關於動態記憶體分配的,在這裡將其重新看了看,覺得還是寫得太淺薄了。因為記憶體是程式啟動並執行“運動場”,對場地的瞭解程度會直接影響到我們程式啟動並執行流暢度和穩定性。
C++提供了操作符new來在堆上分配記憶體,操作符delete來釋放記憶體。有些情況下,我們需要對記憶體的分配和釋放進行更好的控制。許多程式建立和釋放一些重要類的大量的對象,如tree nodes,linked lists links,points,lines,messages,etc.使用通用的記憶體 Clerk如new和delete來進行這些對象的分配和釋放有時將支配程式的已耗用時間和記憶體需求。
兩方面的因素:通用記憶體配置操作的運行和空間的耗費以及不同對象大小引起的記憶體片段。類使用定製的記憶體 Clerk將加快模擬器、編譯器和類似程式的執行速度。
例外一種需要更好的記憶體控制的情況是:需要在有限資源的情況下長時間不間斷啟動並執行程式。即時系統經常需要用最少的耗費來擷取有保證的可預期的記憶體。這也就導致了更好的記憶體控制的需要。一般來說,這些程式都避免使用動態記憶體配置,而使用特殊目的的記憶體 Clerk來管理有限資源。
此外,還有一些情況下由於硬體或系統的要求,需要將對象放在指定的記憶體位置。這也需要進行定製的記憶體管理(通過重載new來加以實現)。
在C++ Release 2.0中,為了滿足以上需求,記憶體管理機製做了相應的修改。主要是引進了operator new [] 和 operator delete []. new操作符的作用範圍(Scope for operator new Functions)
操作符(Operator) 範圍(Scope)
::operator new Global
class-name::operator new Class
operator new的第一個參數必須是類型size_t(在STDDEF.H中定義的類型),傳回型別為void *.
當分配內建(built-in)類型的對象、未包含使用者自訂的new操作符函數的類對象、任何類型的數組時,使用全域new操作符函數。當在類中自訂new操作符時,分配該類對象的記憶體時,調用該類的new操作符。如下:
#include #include class Blanks { public: Blanks(){} void *operator new( size_t stAllocateBlock, char chInit ); }; void *Blanks::operator new( size_t stAllocateBlock, char chInit ) { void *pvTemp = malloc( stAllocateBlock ); if( pvTemp != 0 ) memset( pvTemp, chInit, stAllocateBlock ); return pvTemp; } int main() { Blanks *a5 = new( 0xa5 ) Blanks;//建立對象Blanks,並且初試化為0xa5 return a5 != 0; } |
new操作符可以重載,而delete卻不行。因為等到需要釋放的時候,我們所能得到的就是一個指標。而且該指標可能不是原先的物件類型指標(有可能進行了類型轉換)。實際上,當使用new獲得一個指向一片記憶體的指標時,在該片記憶體前有一個指標(indicator)
,記錄實際分配的記憶體數量。當調用delete時,可以獲知需要釋放的記憶體大小。
數組的釋放(Deallocating Arrays):
void f( ) { X* p1 = new X[10]; //... delete [] X; } |
為什麼不使用delete [10] X;來釋放記憶體?Bjarne Stroustrup稱這種做法容易導致錯誤,而將記錄元素個數的任務放在delete的實現中了。
至於為什麼C++中未內建垃圾收集器(Garbage Collection)的原因,看《C++語言的設計和演化》(En) Bjarne Stroustrup 機械工業出版社(俗稱:D&E)可以得到答案。
此外,C++標準庫中提供了一種智能型指標auto_ptr,這種指標可以協助我們防止“被異常拋出時發生資源泄漏”。但是缺點是該智能型指標不能指向數組,因為其內部釋放記憶體是通過delete而非delete [] 來進行的。所以,只能使用其來指向一個單個對象。
模板部分是C++中比較難的部分,也是C++的魅力所在。以下文字是我以前看過的,具體出處不清楚了。今天稍微整理了一下,作為模板介紹的一個單元。
為什麼要使用模板
對於除類型之外,其餘都相同的函數(譬如quicksort),我們一般有3種解決辦法。
1、針對每個不同的類型重複地編寫函數實體(C語言的做法):
int* quicksort(int a[]) {…… }
double* quicksort(double a[]) {…… }
…
2、使用Object(Java的做法)或者void*
缺點有兩個
效率問題方面也有問題
類型檢查問題
3、使用宏預先處理機制
缺點:只是愚蠢的文本替換,而且也不會考慮範圍和型別安全。
然而,應用模板卻可以避免這些缺點,我們可以編寫:
template
T* quicksort(T a[]) {…… }
優點:
代碼簡潔優雅,所有參數類型都以T來代替,真正實現了類型無關性。
更好的型別安全,所有的類型檢查都是在編譯期進行,而且避免使用指標。
不存在繼承,效率高。(1)沒有虛函數;(2)所有的一切工作都是在編譯期完成,大大提高運行效率。
目的:告訴編譯器如何做出最佳的選擇,而且這種選擇全部是在編譯期完成的。
模板的機制:特化 和 實參演繹
1、特化 基本模板: template class A { // (1) void f(T1 a, T2 b); } 局部特化(偏特化): template class A { // (2) void f(int a, T2 b); } 或者 template> class A { // (3) void f(T a, T b); } 全域特化(顯式特化): template<> class A { void f(int a, int b); // (4) } 使用樣本: A* p1; //將使用(4) ——全域特化 A* p2; //將使用(3) ——局部特化 A* p3; //將使用(2) ——局部特化 A* p4; //將由(1) ——基本模板——產生 //A |
優點:由:全域特化->局部特化->基本模板,這種特化順序的選擇與匹配(重載解析規則)是由編譯器自動進行的,無需人工參與。
可以根據不同的情況(諸如類型不同,條件不同),給出不同的實現,從而獲得更加靈活的針對性。
可以針對任何變化,改善了程式的擴充性。
2 實參演繹
T const& f(T const& a, T const& b) { return a + b; //1處 } int g = f(1,2); |
實際上f(1,2)要匹配的函數是int const& f(int const&,int const&);
而這個函數又是怎麼來的呢?
優點:
再也無需提供一對角括弧和裡面的實參,諸如f(1,2),有了實參演繹,我們就可以寫成f(1,2)。
模板的應用
1、標準庫(STL)——到處都是模板代碼
標準庫=演算法+容器+迭代器
如list /
2、類型無關性(T)
3、trait和policy
(1)trait: 主要用到了許多typedef和特化,指定的是一種特性。
// traits/accumtraits3.hpp template lass AccumulationTraits; c template<> class AccumulationTraits { public: typedef int AccT; static AccT const zero = 0; }; template<> class AccumulationTraits { public: typedef int AccT; static AccT const zero = 0; }; template<> class AccumulationTraits { public: typedef long AccT; static AccT const zero = 0; }; (2)policy:通常表現為某個函數,指定的是一種行為 class SumPolicy { public: template static void accumulate (T1& total, T2 const & value) { total += value; } }; (3)trait和policy的用法: template > class Accum { public: typedef typename Traits::AccT AccT; static AccT accum (T const* beg, T const* end) { AccT total = Traits::zero(); while (beg != end) { Policy::accumulate(total, *beg); ++beg; } return total; } }; |
4、Metaprogramming
編譯期計算、遞迴的思想
5、新形式的設計範本
(第三、第四、第五點以後再詳細介紹)
《C++ Templates中文版》的具體介紹
第1部分介紹了模板的基本概念,以教程的風格來介紹這些基本概念。
第2部分闡述了模板的語言細節,可以作為一本基於模板的構造的參考手冊。
第3部分介紹了C++模板所支援的基本設計技術,範圍覆蓋從微小的概念一直延伸到複雜的用法;一些技術在別的書籍都沒有出現過。
第4部分基於前兩部分,深入討論了各種使用模板的普通應用程式。
學一個月,可以用VC寫一些小程式自己玩玩
學兩個月,可以用VC寫像樣點的東西在周圍人面前炫炫
學三個月,可以用VC給老闆開始幹活了
學六個月,開始重頭去學C++
學一年後,決定要不要繼續,if(繼續) 學習MFC、ATL、STL、C#、BCB、Network、Database、Algorithm... else 開始就是個錯誤
學三年後,學會怎麼來用程式設計語言來解決問題,VC、BCB等都只是解決問題的工具。這時候
你如果還在學C++,你可以從事軟體開發這個很有“前途”的職業了。