基本概念
編程語言
除了C++之外,還有Java、BASIC、COBOL、FORTRAN、PASCAL和C(只是因為它是B語言的后續語言)等編程語言。
所有這些稱為高級語言,因為它們可以比較容易地表達出要計算機完成的工作,而且不針對某臺計算機。
高級語言中的每個源語句一般映射為幾個內部機器指令。
低級語言比較接近內部機器指令,通常稱為匯編語言,一個匯編語言專門用于一種硬件設計,一般一個匯編指令映射為一個內部機器指令。
編程語言簡史
FORTRAN是第一種開發出來的高級語言,第一個FORTRAN編譯器是在19世紀50年代后期開發出來的。
已有40多年的歷史了,目前仍廣泛應用于科學和工程計算中,但C++和其他語言也逐漸進入這些領域。
COBOL語言專門用于商務數據處理應用程序,它的歷史幾乎與FORTRAN語言一樣長,目前幾乎不用COBOL編寫代碼。
BASIC在19世紀70年代誕生,那時已經有了個人計算機的概念。有趣的是,Microsoft銷售的第一個產品是一個BASIC解釋程序。
這種語言所固有的易用性使之很快普及,直到今天仍非常流行。
Java是在19世紀90年代開發的,它最初開發為Oak語言,用于給小型電子設備編程。
1995年,Oak演變為Java語言,可以在Web頁面中內嵌代碼,從那時起直到現在,這已經成為Java的主要用途。
Java成功的主要原因是它的可移植性。Java程序可以在任何支持它的硬件平臺上運行,而且不需要任何修改。
Java語言的語法有許多特性,使它看起來很像C++,但有很大的區別。Java在可移植性方面比C++好,但執行性能比不上C++。
C在上個世紀70年代被開發為一種高級語言,用于低級編程,例如實現操作系統。大多數Unix操作系統就是用C編寫的。
C++是19世紀80年代早期開發的,是一種基于C的面向對象語言。
顧名思義,C++表示C的累加。
由于C++基于C,所以這兩種語言有許多共同的語法和功能,C中所有低級編程的功能都在C++中保留下來。
但是,C++比其前身豐富得多,用途也廣泛得多。
C++對內存管理功能進行了非常大的改進,C++還具有面向對象的功能,所以C在功能上只是C++的一個很小的子集。
C++在適用范圍、性能和功能上也是無可匹敵的。
因此,目前大多數高性能的應用程序和系統仍使用C++編寫。
解釋性程序和編譯性程序的執行過程
無論使用哪種編程語言,編寫出來的程序都是由各個指令或源語句構成的,它們描述了希望計算機執行的動作。
這些指令或源語句統稱為源代碼,存儲在磁盤的源文件中。
任何規模的C++程序都是由若干個源文件組成的。
編程語言的目的是,與計算機可以執行的程序相比,能夠更簡單地描述希望計算機執行的動作。
計算機只能執行包含機器指令(也稱為機器代碼)的程序,不能直接執行我們編寫的程序。
用前面提到的語言編寫的程序基本上有兩種執行方式,在大多數情況下,一種語言會選擇其中一種執行方式。
例如,用BASIC語言編寫的程序通常是解釋性的,
也就是說,另一個稱為解釋器的程序會檢查BASIC源代碼,確定該程序要做什么,再讓計算機完成這些動作。
而C++是一種編譯語言。在執行C++程序之前,必須用另一個程序(即編譯器)把它轉換為機器語言。
編譯器會檢查并分析C++程序,并生成機器指令,以執行源代碼指定的動作。
當然,解釋和編譯都不像這里描述的那樣簡單,但其工作原理就是這樣。
使用解釋性語言,執行過程是間接的,也就是說,每次執行程序時,都需要確定源代碼的意圖。
因此,這種語言比編譯語言的對應程序的執行速度慢得多,有時要慢100倍。
其優點是在運行之前,不必等待程序的編譯。
使用解釋性語言,一旦輸入代碼,就可以立刻執行程序。
任何一種語言要么是解釋性,要么是編譯性的,這通常是由該語言的設計和用途來決定。
前面說過BASIC是一種解釋性語言,但這不是絕對的,目前有許多BASIC語言的編譯器。
沒有所謂“最好”的語言,因為這取決于環境。
看具體環境在意的是開發速度,還是運行速度,又或是移植能力等等。
庫
每次編寫程序時,如果總是要從頭開始編寫,就相當繁瑣。
為了解決這個問題,編程語言通常提供了大量預先編寫好的代碼,以執行標準的操作,這樣就不必重新編寫這些代碼了。
可用于任意程序的標準代碼都保存在一個庫中。
編程語言附帶的庫跟語言本身一樣重要,因為庫的質量和使用范圍對完成某一編程任務所需的時間有非常大的影響。
C++是一種功能強大的語言
C++的ANSI/ISO標準
名稱
C++程序中的許多元素都有用來表示它們的名稱,也稱為標識符。
在C++程序中,可以命名的5種元素是:
函數、變量、類型、標簽、命名空間
關鍵字
C++中有一些保留字,稱為關鍵字,它們在C++語言中有特殊的含義。
C++語句和語句塊
語句是指定程序做什么和程序所處理的數據元素的基本單元。
把名稱引入源文件的語句稱為聲明。
聲明只是引入名稱,指定該名稱表示什么,它與定義不同。
定義是分配一些內存,來包含名稱所指代的內容。
大多數聲明也是定義??????????(這句如何理解??)
變量是內存中一個可以存儲數據項的空間。
下面的語句示例聲明了一個變量名,定義并初始化了一個變量:
double result = 0.0;
這個語句把名稱result聲明為一個double類型的變量(聲明),
把內存分配給該變量(定義),
并設置其初始值為0.0(初始化)。
可以把幾個語句放在一對花括號中,此時這些語句就稱為語句塊。
函數體就是一個語句塊。
語句塊也稱為復合語句,因為在許多情況下,語句塊可以看做是一個語句。
在C++中,在可以放置一個語句的任何地方,都可以放置一個包含在花括號對中的語句塊。
語句塊可以放在其他語句塊內部,這個概念稱為嵌套。語句塊可以嵌套任意級。
語句塊對用于存儲數據項的變量有重要的作用。(變量作用域?)
代碼的顯示樣式
注意使用制表符、空格縮進程序語句,顯示出這些語句的邏輯;再以一致的方式使用定義程序塊的匹配花括號,使塊之間的關系更清晰。
程序結構
每個C++程序都由一個或多個文件組成。
根據約定,用于存儲源代碼的文件有兩類:頭文件和源文件。
頭文件可以包含描述程序所需的數據類型的代碼,以及其他類型的聲明。
頭文件通常用文件擴展名.h來區分,但這不是強制的。
源文件的擴展名是.cpp,它包含了函數聲明,即程序的可執行代碼。這些代碼通常引用在自己的頭文件中定義的數據類型的聲明或定義。
編譯器在編譯代碼時,需要知道這些聲明或定義,因此應在文件的開頭通過#include指令指定.cpp文件中需要的.h文件。
#include指令是編譯器的一個指令,它可以把指定頭文件的內容插入代碼,還需要為代碼需要的標準庫頭文件添加#include指令。
編譯器提供了大量的標準頭文件,其中包含使用標準庫功能所需要的聲明。
實際上,C++的標準頭文件名都沒有擴展名,這就把它們與其他頭文件區分開來。
程序的函數和執行
C++程序至少包含一個函數main(),但程序一般還包含許多其他函數,一些是自己編寫的,另一些是標準庫函數。
執行一個函數稱為調用函數。在調用函數時,可以給它傳送數據項。
在函數執行完后,執行控制返回到調用函數的地方。
函數在執行完畢時,還可以把一個值返回到調用的位置上。
返回值可以存儲起來,以備以后使用,也可以參與某種類型的計算,例如算術表達式的計算。
從源文件中創建可執行文件
從C++源代碼中創建可以執行的程序模塊需要兩步:
第一步是編譯器把每個.cpp文件轉換為對象文件,其中包含了與源文件內容對應的機器碼。
第二步是鏈接程序把編譯器生成的對象文件合并到包含完整可執行程序的文件中。
編譯器把每個源文件看作一個獨立的實體,為每個.cpp文件生成一個對象文件。
然后在鏈接步驟中,把程序的對象文件和必要的庫函數組合到一個可執行文件中。
實際上,編譯是一個迭代的過程,編寫源碼,編譯,發現錯誤,修改源碼,再編譯,發現錯誤,再修改,再編譯,……
編譯
源文件的編譯過程包含兩個主要階段,而它們之間的轉換是自動的。
第一個階段是預處理階段,在正式的編譯階段之前進行。
預處理階段將根據已放置在文件中的預處理指令來修改源文件的內容。
#include指令就是一個預處理指令,它把頭文件的內容添加到.cpp文件中。還有其他許多預處理指令。
這個在編譯之前修改源文件的方式提供了很大的靈活性,以適應不同的計算機和操作系統環境。
一個環境需要的代碼跟另一個環境所需的代碼可能有所不同,因為可用的硬件或操作系統是不同的。
在許多情況下,可以把用于不同環境的代碼放在同一個文件中,再在預處理階段修改代碼,使之適應當前的環境。
預處理器一般不能獨立于編譯器來執行,調用編譯器會自動執行預處理過程,之后才編譯代碼。
鏈接
編譯器為給定源文件輸出的是機器碼,執行這個過程需要較長時間。
在對象文件之間并沒有建立任何連接。
對應于某個源文件的對象文件包含在其他源文件中的定義的函數引用或其他指定項的引用,而這些函數或項仍沒有被解析。
同樣,也沒有建立同庫函數的鏈接。
實際上,這些函數的代碼并不是文件的一部分。
這些工作是由鏈接程序完成的。
鏈接程序把所有對象文件中的機器碼組合在一起,
并解析它們之間的交叉引用。
它還集成了對象模塊所使用的庫函數的代碼。
這是鏈接程序的一種簡化表示,因為這里假定在可執行模塊中,模塊之間的所有鏈接都是靜態建立的。
實際上有些鏈接是動態的,即這些鏈接是在程序執行時建立的。
鏈接程序靜態地建立函數之間的鏈接,即在程序執行之前建立組成程序的源文件中所包含的函數鏈接。
動態建立的函數之間的鏈接(在程序執行過程中建立的鏈接)將函數編譯并鏈接起來,創建另一種可執行模塊——動態鏈接庫或共享庫。
動態鏈接庫中的函數鏈接是程序調用函數時才建立的,在程序調用之前,該鏈接是不存在的。
動態鏈接庫優點:
動態鏈接庫中的函數可以在幾個并行執行的程序之間共享,在執行的多個函數需要動態鏈接庫中的函數所提供的服務時,這將節省同一個函數占用的內存空間。
動態鏈接庫在調用其中的函數之前是不會加載到內存中的,也就是說,如果不使用給定動態鏈接庫中的函數,該動態鏈接庫就不會占用內存空間。
動態鏈接庫是與操作系統緊密相關的一個系統功能。
C++源字符
編寫C++語句要使用基本源字符集,這些是在C++源文件中可以顯式使用的字符集。
包括:大小寫字母,數字,控制字符,一些特殊字符。
在C++中使用的字符定義并沒有說明字符的編碼方式。編譯器將決定用于編寫C++源代碼的字符在計算機上如何表示。
通用字符集(Universal Character Set, UCS)。
由UCS標準定義的字符編碼與Unicode定義的編碼相同。
三字符序列
就是用于表示另一個字符的三個字符序列。以前為了表示鍵盤上沒有的字符,這是必不可少的一種方法。
編譯器會用對應的字符替代它們,再對源代碼進行其他處理。
轉義序列
通過轉義序列可以把控制字符輸入字符常量。轉義序列是指定字符的一種間接方式,通常以一個反斜杠\開頭。
由于反斜框表示轉義序列的開始,因此把反斜杠字符輸入一個字符常量的唯一方式是使用兩個連續的反斜杠。
轉義序列還提供了用鍵盤不支持的語言來表示字符的一種通用方式,因為可以使用十六進制(基數是16)或八進制(基數是8)數字前置一個反斜杠來指定字符的編碼。
由于使用了數字編碼,可以用這種方式指定任何字符。
在C++中,十六進制數據以x或X開頭。
還可以使用至多3個八進制數字前置一個反斜杠來表示字符。例如\165。沒有x或X,就表示該編碼應解釋為一個八進制數字。
cout << "\n\" Least said\n\t\tsoonest mended.\ "\n\a";
雙引號之間的字符串稱為字符串字面量。
雙引號字符表示該字符串字面量的開始和結束,它們不是字符串的一部分。
字符串內部的雙引號不會解釋為字符串字面量的結束,這是因為每個雙引號的前面都有一個反斜杠,表示這是一個轉義序列。
語句中的空白
除了在語句的元素之間或引號中的字符串內用作分隔符之外,編譯器會忽略空白。
因此可以在代碼中包含任意多個空白,使程序的可讀性更高。
在一些編程語言中,語句的結尾是代碼行的末尾,但在C++中,語句的結尾用分號表示。
因此,可以把一個語句分散放在好幾行代碼行上。
程序的注釋
C++中注釋有兩種形式:單行和多行。
單行注釋以雙斜杠開頭(//)。
編譯器會忽略雙斜杠后面的所有內容。
多行注釋以/*開頭,以*/結尾。在/*和*/之間的所有內容都被忽略。
注意多行注釋不能嵌套,否則會使編譯器發出錯誤消息。
標準庫
標準庫包含了大量的函數和其他支持實體,增加和擴展了C++的基本語言功能。
標準庫的內容是C++的一部分,在語言的語法和語義方面跟C++相同。
C++的標準定義了這兩者,所以每個符合該標準的編譯器都提供了完整的標準庫。
標準庫的范圍是很特殊的。
使用該標準庫將獲得非常多的功能,包括基本元素如基本語言支持、
輸入輸出函數和異常處理(異常是在程序執行中發生的偶然事件,常常是某種錯誤)、
實用函數,數學例程和各種預先編寫好并測試通過的功能。
在程序執行過程中可借助這些功能來存儲和管理數據。
使用標準庫所需要的定義和聲明位于標準頭文件中。
C++標準庫中的幾乎所有內容都是在命名空間std中定義的。
用C++編程
過程化編程方法和面向對象編程方法
小結
C++程序至少包含一個main()函數。
函數的可執行部分由包含在一對花括號中的語句組成。
一對花括號定義了一個語句塊。
在C++中,語句用分號結束。
關鍵字是C++中有特殊含義的一組保留字。程序中的實體不能與C++語言中的任何關鍵字同名。
C++程序包含在一個或多個文件中。
定義函數的代碼通常存儲在擴展名為.cpp的文件中。
定義數據類型的代碼通常存儲在擴展名為.h的頭文件中。
C++標準庫提供了支持和擴展C++語言的大量功能。
C++中的輸入和輸出是利用流來執行的,并且需要使用插入和撮運算符,即<<和>>。
面向對象的編程方式需要定義專門用于某程序的新數據類型。一旦定義好需要的數據類型,就可以根據這些新數據類型來編寫程序。