《C++ Primer Plus》第二章

第一個C++程序

#include <iostream>
int main()
{
	using namespace std;
	cout << "hello.";
	cout << endl;
	return 0;
}

在某些窗口環境下,程序會在獨立窗口執行然後直接結束自動關閉。所以可以在return語句前加上cin.get()來阻塞程序。

方法頭

int main()

這個就是方法頭,最左邊的int是方法返回值的類型,main是方法的名字,括號內是調用該方法需要傳入的參數的類型和個數。這裏沒寫意味着該方法不需要傳入參數。更清晰的寫法應該是:

int main(void)

註釋

使用雙斜槓"//“作爲開頭來寫一句註釋。註釋是用於給代碼的讀者解釋代碼的,編譯器在編譯程序時會忽略這些註釋。
從//開始一直到該行結束都算是註釋。所以註釋可以單獨寫一行也可以寫在一行代碼的後面。
另外,C++也可以使用”/“和”/"來標記一段註釋的開始和結束。這樣的標記法就允許編寫多行的註釋。

//第一個C++程序
#include <iostream>
int main() //方法頭
{
	using namespace std;
	cout << "hello.";
	cout << endl;
	return 0;
	/*
	多
	行
	注
	釋
	*/
}

預處理和iostream

#include <iostream>

這一句將iostream文件的內容加到了程序中。這是典型的預處理行爲:在編譯之前添加或替換源代碼的文本。也就是在程序被編譯時,include這一句會被iostream的文件內容替代。
至於這樣做的目的,是因爲cout和cin都是在iostream文件中定義的對象,要使用這兩個對象,就要引入iostream文件。

頭文件(head file)

iostream被稱作引入文件也稱作頭文件。C++有很多頭文件,欸一個都包含了大量實用工具。C語言用h這個擴展名來簡單區分頭文件的名字與類型。比如C語言中math.h是支持多種數學方法的頭文件。現在h擴展名在C語言的頭文件中還有保留,C++也可以用,但C++的頭文件都是沒有擴展名的。C++很多頭文件都是將C的頭文件的擴展名去掉然後在前面加一個’c’。比如math.h變成cmath.

命名空間(namespace)

如果程序引入的不是iostream.h二十iostream,那麼就需要額外加入以下語句:

using namespace std;

這是using指令,引入的是命名空間std。
命名空間是一個用於簡化大型程序編寫和整合多來源前置代碼的C++特性。多來源前置代碼會導致的問題是兩個不同的頭文件中可能會存在兩個相同名字的對象或方法。比如:

#include <hongkong>
#include <shandong>

int main()
{
	tony();
}

如果hongkong頭文件中定義了tony方法,shandong頭文件也定義了tony方法。那麼編譯器在編譯以上程序時就沒法分辨main方法中調用的tony是哪個頭文件中定義的方法。這時就需要命名空間這個概念出手。命名空間機制要求hongkong和shandong都把自己定義的東西放到自己的命名空間內,然後程序就可以使用命名空間來標識被調用的方法的來源。比如:

#include <hongkong>
#include <shandong>

int main()
{
	hongkong::tony();
}

這樣編譯器就知道main方法調用的是hongkong頭文件定義的tony方法。同樣的,上面的第一個C++程序可以寫成:

#include <iostream>
int main()
{
	std::cout << "hello.";//std是iostream的命名空間的名字
	std::cout << endl;
	return 0;
}

但是每個cout都要標上std挺麻煩的。所以程序可以用using語句將一個命名空間中的所有方法和對象都引入到程序中。一句using namespace std,下面的所有cout就都不需要標識了。
但是這種一刀切的方法其實和命名空間的目的是背離的,在大型程序中可能會導致潛在問題,所以using指令可以僅引入頭文件中的單個對象或方法:

using hongkong::tony;
using std::cout;

關於using指令會在第九章更詳細地進行討論。

cout

cout << "hello.";
cout << endl;

最左是cout對象,中間是操作符,最右是要輸出的字符串。
endl則是一個特別的C++標識符,意爲endline,也即是結束該行。這種對cout有特別意義的稱作manipulator(操作符),都在iostream中定義。
當然換行方式不止一種,還有一種是使用"\n"換行符。

cout << "hello.\n";

C++源碼格式

有些語言是基於行的,比如FORTRAN。它們是靠換行符分隔語句的。一行就是一句代碼。但C++是用分號";"來分隔語句的,也就是說,C++的一句代碼是可以任意換行的。比如第一個C++程序可以寫成如下樣子:

#include <iostream>
int 
	main
()
{
	using
	namespace 
std;
		std::
cout <<        "hello.";
	std::cout          << endl;return 0;
}

但這很明顯是反人類的。這樣的代碼莫說別人讀不懂,代碼作者過一段時間自己也會難以讀懂。所以寫代碼需要遵循一定的格式才能更合理高效。
另外,C++代碼也不是可以隨意換行的,在單個元素(比如名字,關鍵字,字符串)的中間是不能換行或者加空格的。比如:

#include <iostream>
int main()
{
	using namespace std;
	cout << "hel
	lo.";//字符串換行不行
	co  ut << endl;//對象名字中間加空格不行
	return 0;
}

token和空格

token是一個不可分割的概念。兩個token之間必須用空格或tab或回車分開。空格,tab和回車同城空白區(white space)。單字符的token(比如括號和逗號)不需要空白區分隔。具體示例如下:

return0;//不行,return和0沒分開
return(0);//可以,括號是單字符token,可以省略空白區
return (0);//可以
intmain();//不行,int和main沒有分隔
int main();//可以,括號不需要分隔

C++代碼樣式

理論上C++代碼怎麼寫都是無所謂的,但是如前言提到的,遵循一定格式編寫代碼效率會更高。比如:

  • 一句一行
  • 標識方法的開始與結束的大括號都各佔一行
  • 方法裏的語句不要和大括號粘在一起
  • 方法名和小括號之間不要加空白區

前三條是爲了代碼的乾淨和可讀性。第四條是爲了將方法和其他帶有小括號的C++結構(比如循環)區分。

C++語句

C++程序是方法的集合,方法是語句的集合。

#include <iostream>

int main()
{
	using namespace std;
	
	int carrots;
	
	carrots = 25;
	cout << "I have " << carrots << " carrots.";
	return 0;
}

以上程序使用了兩種新的語句:聲明和賦值語句。另外還有cout的新用法。接下來逐條介紹一下這些語句。
(另外提一句,上方程序用空行將聲明語句與其他語句隔開了,這其實是C語言的習慣,在C++不常見。不過這都是習慣問題,不重要。)

聲明語句

int carrots;

左邊是聲明的變量的類型,右邊是變量的名字,最後分號結束。
額外說一下,爲什麼要標明變量的類型呢?在其他的語言比如Python,是可以只聲明變量名字而省略變量的類型。但這有個潛在問題是這會使聲明語句和賦值語句變得無法分辨,從而提高代碼維護難度。比如:

DarkFantasy = 1
...
DrakFantasy = 2

假設程序原本是想在第二句將DarkFantasy賦值爲2.但因爲拼寫錯誤,第二句實際上是聲明瞭一個新的變量DrakFantasy並賦值爲2.這就會導致程序出現bug並且由於這裏沒有語法錯誤,程序員很難發現這裏的拼寫錯誤。

賦值語句

carrots = 25;

左邊是被賦值的變量的名字,中間是賦值符號"=",右邊是要賦值的值25.
一個不太常用的C++特性是程序可以連續地使用等號:

jack = david = mike = 6;

這一句是從右到左執行的,先將6賦值給mike,再把mike的值賦值給david,再把david的值賦值給jack。也就是上方語句等價於:

mike = 6;
david = mike;
jack = david;

cout新用法

cout << carrots;

這一句向cout傳入了carrots這個變量。程序不會輸出carrots這個詞,而會輸出變量的值。這裏面其實分爲兩步。首先cout用carrots的值,比如25,替代carrots。然後,它再將25這個值轉換成正確的輸出符號。

也就是說,cout既能輸出字符串也能輸出數字。這聽上去好像不怎麼厲害,但實際上字符串“25”和數字25是不太一樣的。對於這個字符串,程序是存儲了‘2’這個字符和‘5’這個字符。但對於數字,程序則是存儲了25這個值。所以從數字到字符串,是要經過翻譯轉換的。

更多的C++語句

cin

cin >> carrots;

這個語句將鍵盤輸入的值賦值給carrots。左邊是cin對象(同樣也是iostream中定義的對象),中間是操作符,右邊是被賦值的變量的名字。C++將程序的輸出看做從程序流出的字符流,而輸入則是流入程序的字符流。iostream將cin和cout定義爲輸入輸出的象徵。就像cout可以將數值轉爲字符輸出一樣,cin可以將接收的字符轉爲數值然後賦值給變量。

用cout進行連接

在上上段程序中就出現了用cout進行連續輸出:

cout << "I have " << carrots << " carrots." << endl;

這一句其實等價於:

cout << "I have ";
cout << carrots;
cout << " carrots.";
cout << endl;

甚至,因爲C++中空格和回車同樣是用於分隔token的空白區,所以還可以採用如下寫法:

cout << "I have "
	 << carrots
	 << " carrots."
	 << endl;

cin與cout,類的初識

cin和cout其實就是類。類是OOP(object-oriented-programming,面向對象編程)的核心概念。簡單來說類是用戶定義的一個數據類型。要定義一個類,要描述它包含的數據以及可以對數據進行的操作。對象是類的一個實例。

方法

方法是C++程序的基礎並且是OOP變成的重要概念,所以程序與必須對方法這個概念儘可能熟悉。不過關於方法的許多內容是比較進階的內容,要等到第七第八章纔會講到。現在先看看方法的一些基礎特性。
C++方法分兩種,有返回值的和沒有的。你可以在標準C++庫裏找例子,也可以自己寫幾個。

有返回值的

有返回值的方法可以用來給變量賦值,或者用到別的什麼表達式了。比如C和C++的庫裏都有一個方法叫sqrt,這個方法會返回傳入的值的平方根。

x = sqrt(9);

這一句向sqrt方法傳入了參數9,方法返回了9的平方根,然後程序將sqrt的返回值賦值給x。這個表達式稱作方法調用(function call),sqrt是被調用方法(called function),而包含這個調用語句的方法叫做發起調用方法(calling function)。
括號裏的9是傳入到方法的參數(argument or parameter)。sqrt接收這個參數,算出平方根,然後返回到發起調用方法。
這就是調用語句的全部。另外要提到就是在調用發起之前,編譯器要知道這個方法需要傳入的參數的類型和個數以及返回值的類型,以便檢查程序有沒有錯誤。所以需要引入方法原型(function prototype statement)。
方法原型語句格式如下:

double sqrt(double)

方法詳情

有些方法需要很多的參數,這些參數用逗號分隔:

double add(int, int);

也有些方法不要參數:

int main(void);

和其他語言不一樣的是,C++裏方法即便不要參數,也要把括號寫上。
還有些方法是沒有返回值的,這時就又用到void關鍵字:

void show(int);

沒有返回值的方法就不能用於賦值了。

用戶自定義方法

標準C++庫提供了超過140種預定義的方法,寫程序時有合用的就用。但很多時候並不能找到合用的方法,這時就需要自定義方法。每個C++程序都必須有的main方法就是一個自定義方法。

方法格式

聲明方法的基本格式如下:

type function_name(argument_list)
{
	statements
}

要注意的是C++和C一樣而和Pascal不同,C++不允許在一個方法定義中定義另一個方法。每個方法要平等獨立地被聲明。

在多方法程序中使用using指令

先前提到using指令引入命名空間。在多方法程序中,可以將using放在方法體外,讓引入的命名空間對後續所有方法都可用。也可以將指令放在方法定義內,讓引入的命名空間只對該方法有效。
總結一下using指令用法:

  1. 放在方法體外,命名空間對後續所有方法可用;
  2. 方法某個方法定義內,命名空間僅對該方法可用;
  3. 使用類似using std::cout的方式引入明明空間內單個對象
  4. 不使用using指令,在每個對象前加上對應命名空間的名字。比如std::cout << “hello.”;
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章