一文讓你學完C++,乾貨收藏!!!

C語言與CPP程式設計發表於2020-11-22

我們今天帶來了C++的基礎知識大彙總,當然這是精簡版的,但是篇幅也不少,應該說該有的也都有了,建議大家收藏慢慢學習,同時希望對大家的C++學習有所幫助。

一 、從”hello world“ 入門C++!

C++總覽簡介

C++ 是一種靜態型別的、編譯式的、通用的、大小寫敏感的、不規則的程式語言,支援過程化程式設計、物件導向程式設計和泛型程式設計。

C++ 被認為是一種中級語言,它綜合了高階語言和低階語言的特點。

C++ 是由 Bjarne Stroustrup 於 1979 年在新澤西州美利山貝爾實驗室開始設計開發的。C++ 進一步擴充和完善了 C 語言,最初命名為帶類的C,後來在 1983 年更名為 C++。

C++ 是 C 的一個超集,事實上,任何合法的 C 程式都是合法的 C++ 程式。

注意:使用靜態型別的程式語言是在編譯時執行型別檢查,而不是在執行時執行型別檢查。

物件導向程式設計

c++最大的亮點就是物件導向程式設計理念的運用。包括物件導向開發的四大特性:

  •     封裝

  •     抽象

  •     繼承

  •     多型

C++的組成部分

標準的 C++ 由三個重要部分組成:

  •     核心語言,提供了所有構件塊,包括變數、資料型別和常量,等等。

  •     C++ 標準庫,提供了大量的函式,用於操作檔案、字串等。

  •     標準模板庫(STL),提供了大量的方法,用於運算元據結構等。

C++的標準

對一門程式語言來說,遵循統一的標準是必需的。下面的表格列出了c++標準的發展歷史。

釋出時間文件通稱備註
2015ISO/IEC TS 19570:2015-用於平行計算的擴充套件
2015ISO/IEC TS 18822:2015-檔案系統
2014ISO/IEC 14882:2014C++14第四個C++標準
2011ISO/IEC TR 24733:2011-十進位制浮點數擴充套件
2011ISO/IEC 14882:2011C++11第三個C++標準
2010ISO/IEC TR 29124:2010-數學函式擴充套件
2007ISO/IEC TR 19768:2007C++TR1C++技術報告:庫擴充套件
2006ISO/IEC TR 18015:2006-C++效能技術報告
2003ISO/IEC 14882:2003C++03第二個C++標準

C++ 程式結構

讓我們看一段簡單的程式碼,可以輸出單詞 Hello World。

#include <iostream>
using namespace std;
// main() 是程式開始執行的地方
int main()
{
cout << "Hello World"; // 輸出 Hello World
return 0;
}

讓我們一起來研究一下上面的程式碼結構:

C++ 語言定義了一些標頭檔案,這些標頭檔案包含了程式中必需的或有用的資訊。上面這段程式中,包含了標頭檔案 <iostream>。

下一行 using namespace std; 告訴編譯器使用 std 名稱空間。名稱空間是 C++ 中一個相對新的概念。

下一行 // main() 是程式開始執行的地方 是一個單行註釋。單行註釋以 // 開頭,在行末結束。

下一行 int main() 是主函式,程式從這裡開始執行。

下一行 cout << "Hello World"; 會在螢幕上顯示訊息 "Hello World"。

下一行 return 0; 終止 main( )函式,並向呼叫程式返回值 0。

C++ 中的分號 & 語句塊

在 C++ 中,分號是語句結束符。也就是說,每個語句必須以分號結束。它表明一個邏輯實體的結束。

例如:下面就一共有兩條語句。

x = y;
y = x+1;

語句塊是一組使用大括號括起來的按邏輯連線的語句。例如:

{
cout << "Hello World"; // 輸出 Hello World
return 0;
}

C++ 關鍵字

下表列出了 C++ 中的保留字。這些保留字不能作為常量名、變數名或其他識別符號名稱。

asmelsenewthis
autoenumoperatorthrow
boolexplicitprivatetrue
breakexportprotectedtry
caseexternpublictypedef
catchfalseregistertypeid
charfloatreinterpret_casttypename
classforreturnunion
constfriendshortunsigned
const_castgotosignedusing
continueifsizeofvirtual
defaultinlinestaticvoid
deleteintstatic_castvolatile
dolongstructwchar_t
doublemutableswitchwhile
dynamic_castnamespacetemplate 

C++ 識別符號

C++ 識別符號是用來標識變數、函式、類、模組,或任何其他使用者自定義專案的名稱。一個識別符號以字母 A-Z 或 a-z 或下劃線 _ 開始,後跟零個或多個字母、下劃線和數字(0-9),不允許改變識別符號組成規則。

下面列出幾個有效的識別符號:

test
_temp

二 、 c++基本資料型別及流控制語句詳解

C++ 陣列

C++ 支援陣列資料結構,它可以儲存一個固定大小的相同型別元素的順序集合。陣列是用來儲存一系列資料,但它往往被認為是一系列相同型別的變數。

陣列的宣告並不是宣告一個個單獨的變數,比如 number0、number1、...、number99,而是宣告一個陣列變數,比如 numbers,然後使用 numbers[0]、numbers[1]、...、numbers[99] 來代表一個個單獨的變數。陣列中的特定元素可以通過索引訪問。

所有的陣列都是由連續的記憶體位置組成。最低的地址對應第一個元素,最高的地址對應最後一個元素。

宣告陣列

在 C++ 中要宣告一個陣列,需要指定元素的型別和元素的數量,如下所示:

type arrayName [ arraySize ];

這叫做一維陣列。arraySize 必須是一個大於零的整數常量,type 可以是任意有效的 C++ 資料型別。例如,要宣告一個型別為 double 的包含 10 個元素的陣列 balance,宣告語句如下:

double balance[10];

現在 balance 是一個可用的陣列,可以容納 10 個型別為 double 的數字。

初始化陣列

在 C++ 中,可以逐個初始化陣列,也可以使用一個初始化語句,如下所示:

double balance[5] = {1000.0, 2.0, 3.4, 7.0, 50.0};

大括號 { } 之間的值的數目不能大於我們在陣列宣告時在方括號 [ ] 中指定的元素數目。

如果省略掉了陣列的大小,陣列的大小則為初始化時元素的個數。因此,如果:

double balance[] = {1000.0, 2.0, 3.4, 7.0, 50.0};

將建立一個陣列,它與前一個例項中所建立的陣列是完全相同的。

下面是一個為陣列中某個元素賦值的例項:

balance[4] = 50.0;

上述的語句把陣列中第五個元素的值賦為 50.0。所有的陣列都是以 0 作為它們第一個元素的索引,也被稱為基索引,陣列的最後一個索引是陣列的總大小減去 1。以下是上面所討論的陣列的的圖形表示:

訪問陣列元素

陣列元素可以通過陣列名稱加索引進行訪問。元素的索引是放在方括號內,跟在陣列名稱的後邊。例如:

double salary = balance[9];

上面的語句將把陣列中第 10 個元素的值賦給 salary 變數。下面的例項使用了上述的三個概念,即,宣告陣列、陣列賦值、訪問陣列:

#include <iostream>using namespace std; #include <iomanip>using std::setw; int main (){   int n[ 10 ]; // n 是一個包含 10 個整數的陣列    // 初始化陣列元素             for ( int i = 0; i < 10; i++ )   {      n[ i ] = i + 100; // 設定元素 i 為 i + 100   }   cout << "Element" << setw( 13 ) << "Value" << endl;    // 輸出陣列中每個元素的值                        for ( int j = 0; j < 10; j++ )   {      cout << setw( 7 )<< j << setw( 13 ) << n[ j ] << endl;   }    return 0;}

C++ 字串

C++ 提供了以下兩種型別的字串表示形式:

  • C 風格字串

  • C++ 引入的 string 類型別

C 風格字串

C 風格的字串起源於 C 語言,並在 C++ 中繼續得到支援。字串實際上是使用 null 字元 '\0' 終止的一維字元陣列。因此,一個以 null 結尾的字串,包含了組成字串的字元。

下面的宣告和初始化建立了一個 "Hello" 字串。由於在陣列的末尾儲存了空字元,所以字元陣列的大小比單詞 "Hello" 的字元數多一個。

char greeting[6] = {'H', 'e', 'l', 'l', 'o', '\0'};

依據陣列初始化規則,可以把上面的語句寫成以下語句:

char greeting[] = "Hello";

以下是 C/C++ 中定義的字串的記憶體表示:

其實,不需要把 null 字元放在字串常量的末尾。C++ 編譯器會在初始化陣列時,自動把 '\0' 放在字串的末尾。讓我們嘗試輸出上面的字串:

例項

#include <iostream> 
using namespace std;
 int main (){ 
   char greeting[6] = {'H', 'e', 'l', 'l', 'o', '\0'};   
    cout << "Greeting message: ";  
     cout << greeting << endl;  
       return 0;
 }

當上面的程式碼被編譯和執行時,它會產生下列結果:

Greeting message: Hello

C++ 中有大量的函式用來操作以 null 結尾的字串:supports a wide range of functions that manipulate null-terminated strings:

序號函式 & 目的

1

strcpy(s1, s2); 複製字串 s2 到字串 s1。

2

strcat(s1, s2); 連線字串 s2 到字串 s1 的末尾。

3

strlen(s1); 返回字串 s1 的長度。

4

strcmp(s1, s2); 如果 s1 和 s2 是相同的,則返回 0;如果 s1<s2 則返回值小於 0;如果 s1>s2 則返回值大於 0。

5

strchr(s1, ch); 返回一個指標,指向字串 s1 中字元 ch 的第一次出現的位置。

6

strstr(s1, s2); 返回一個指標,指向字串 s1 中字串 s2 的第一次出現的位置。


下面的例項使用了上述的一些函式:

例項

#include <iostream>#include <cstring> using namespace std; int main (){   char str1[11] = "Hello";   char str2[11] = "World";   char str3[11];   int  len ;    // 複製 str1 到 str3   strcpy( str3, str1);   cout << "strcpy( str3, str1) : " << str3 << endl;    // 連線 str1 和 str2   strcat( str1, str2);   cout << "strcat( str1, str2): " << str1 << endl;    // 連線後,str1 的總長度   len = strlen(str1);   cout << "strlen(str1) : " << len << endl;    return 0;}

當上面的程式碼被編譯和執行時,它會產生下列結果:

strcpy( str3, str1) : Hellostrcat( str1, str2): HelloWorldstrlen(str1) : 10C++ 中的 String 類

C++ 中的 string 類

C++ 標準庫提供了 string 類型別,支援上述所有的操作,另外還增加了其他更多的功能。現在讓我們先來看看下面這個例項:

例項

#include <iostream>
#include <string>
 
using namespace std;
 
int main ()
{
   string str1 = "Hello";
   string str2 = "World";
   string str3;
   int  len ;
 
   // 複製 str1 到 str3
   str3 = str1;
   cout << "str3 : " << str3 << endl;
 
   // 連線 str1 和 str2
   str3 = str1 + str2;
   cout << "str1 + str2 : " << str3 << endl;
 
   // 連線後,str3 的總長度
   len = str3.size();
   cout << "str3.size() :  " << len << endl;
 
   return 0;
}

當上面的程式碼被編譯和執行時,它會產生下列結果:

str3 : Hello
str1 + str2 : HelloWorld
str3.size() : 10

C++ 迴圈

有的時候,可能需要多次執行同一塊程式碼。一般情況下,語句是順序執行的:函式中的第一個語句先執行,接著是第二個語句,依此類推。

程式語言提供了允許更為複雜的執行路徑的多種控制結構。

迴圈語句允許我們多次執行一個語句或語句組,下面是大多數程式語言中迴圈語句的一般形式:

迴圈型別

C++ 程式語言提供了以下幾種迴圈型別。

迴圈型別描述

while 迴圈

當給定條件為真時,重複語句或語句組。它會在執行迴圈主體之前測試條件。

for 迴圈

多次執行一個語句序列,簡化管理迴圈變數的程式碼。

do...while 迴圈

除了它是在迴圈主體結尾測試條件外,其他與 while 語句類似。

巢狀迴圈

可以在 while、for 或 do..while 迴圈內使用一個或多個迴圈。

迴圈控制語句

迴圈控制語句更改執行的正常序列。當執行離開一個範圍時,所有在該範圍中建立的自動物件都會被銷燬。

C++ 提供了下列的控制語句。

控制語句描述

break 語句

終止 loop 或 switch 語句,程式流將繼續執行緊接著 loop 或 switch 的下一條語句。

continue 語句

引起迴圈跳過主體的剩餘部分,立即重新開始測試條件。

goto 語句

將控制轉移到被標記的語句。但是不建議在程式中使用 goto 語句。

無限迴圈

如果條件永遠不為假,則迴圈將變成無限迴圈。for 迴圈在傳統意義上可用於實現無限迴圈。由於構成迴圈的三個表示式中任何一個都不是必需的,可以將某些條件表示式留空來構成一個無限迴圈。

例項

#include <iostream>
using namespace std;
 
int main ()
{
 
   for( ; ; )
   {
      printf("This loop will run forever.\n");
   }
 
   return 0;
}

當條件表示式不存在時,它被假設為真。也可以設定一個初始值和增量表示式,但是一般情況下,C++ 程式設計師偏向於使用 for(;;) 結構來表示一個無限迴圈。

注意:可以按 Ctrl + C 鍵終止一個無限迴圈。

C++ 判斷

判斷結構要求程式設計師指定一個或多個要評估或測試的條件,以及條件為真時要執行的語句(必需的)和條件為假時要執行的語句(可選的)。

下面是大多數程式語言中典型的判斷結構的一般形式:

判斷語句

C++ 程式語言提供了以下型別的判斷語句。

語句描述

if 語句

一個 if 語句 由一個布林表示式後跟一個或多個語句組成。

if...else 語句

一個 if 語句 後可跟一個可選的 else 語句,else 語句在布林表示式為假時執行。

巢狀 if 語句

可以在一個 if 或 else if 語句內使用另一個 if 或 else if 語句。

switch 語句

一個 switch 語句允許測試一個變數等於多個值時的情況。

巢狀 switch 語句

可以在一個 switch 語句內使用另一個 switch 語句。

 

三 、 c++進階 基本輸入輸出、指標、引用

C++ 基本的輸入輸出

今天我們來熟悉一下C++ 程式設計中最基本和最常見的 I/O 操作。

C++ 的 I/O 發生在流中,流是位元組序列。如果位元組流是從裝置(如鍵盤、磁碟驅動器、網路連線等)流向記憶體,這叫做輸入操作。如果位元組流是從記憶體流向裝置(如螢幕、印表機、磁碟驅動器、網路連線等),這叫做輸出操作。

I/O 庫標頭檔案

下列的標頭檔案在 C++ 程式設計中很重要。

標頭檔案

函式和描述

<iostream>

該檔案定義了 cin、cout、cerr 和 clog 物件,分別對應於標準輸入流、標準輸出流、非緩衝標準錯誤流和緩衝標準錯誤流。

<iomanip>

該檔案通過所謂的引數化的流操縱器(比如 setw 和 setprecision),來宣告對執行標準化 I/O 有用的服務。

<fstream>

該檔案為使用者控制的檔案處理宣告服務。我們將在檔案和流的相關章節討論它的細節。

標準輸出流(cout)

預定義的物件 cout 是 iostream 類的一個例項。cout 物件"連線"到標準輸出裝置,通常是螢幕。cout 是與流插入運算子 << 結合使用的,如下所示:

例項

#include <iostream>
 
using namespace std;
 
int main( )
{
   char str[] = "Hello C++";
 
   cout << "Value of str is : " << str << endl;
}

當上面的程式碼被編譯和執行時,它會產生下列結果:

Value of str is : Hello C++

C++ 編譯器根據要輸出變數的資料型別,選擇合適的流插入運算子來顯示值。<< 運算子被過載來輸出內建型別(整型、浮點型、double 型、字串和指標)的資料項。

流插入運算子 << 在一個語句中可以多次使用,如上面例項中所示,endl 用於在行末新增一個換行符。

標準輸入流(cin)

預定義的物件 cin 是 iostream 類的一個例項。cin 物件附屬到標準輸入裝置,通常是鍵盤。cin 是與流提取運算子 >> 結合使用的,如下所示:

例項

#include <iostream>
 
using namespace std;
 
int main( )
{
   char name[50];
 
   cout << "請輸入您的名稱:";
   cin >> name;
   cout << "您的名稱是:" << name << endl;
 
}

當上面的程式碼被編譯和執行時,它會提示使用者輸入名稱。當使用者輸入一個值,並按Enter鍵,就會看到下列結果:

請輸入您的名稱:cplusplus
您的名稱是:cplusplus

C++ 編譯器根據要輸入值的資料型別,選擇合適的流提取運算子來提取值,並把它儲存在給定的變數中。

流提取運算子 >> 在一個語句中可以多次使用,如果要求輸入多個資料,可以使用如下語句:

cin >> name >> age;

這相當於下面兩個語句:

cin >> name;
cin >> age;

標準錯誤流(cerr)

預定義的物件 cerr 是 iostream 類的一個例項。cerr 物件附屬到標準錯誤裝置,通常也是螢幕,但是 cerr 物件是非緩衝的,且每個流插入到 cerr 都會立即輸出。

cerr 也是與流插入運算子 << 結合使用的,如下所示:

例項

#include <iostream>
 
using namespace std;
 
int main( )
{
   char str[] = "Unable to read....";
 
   cerr << "Error message : " << str << endl;
}

當上面的程式碼被編譯和執行時,它會產生下列結果:

Error message : Unable to read....

標準日誌流(clog)

預定義的物件 clog 是 iostream 類的一個例項。clog 物件附屬到標準錯誤裝置,通常也是螢幕,但是 clog 物件是緩衝的。這意味著每個流插入到 clog 都會先儲存在緩衝在,直到緩衝填滿或者緩衝區重新整理時才會輸出。

clog 也是與流插入運算子 << 結合使用的,如下所示:

例項

#include <iostream>
 
using namespace std;
 
int main( )
{
   char str[] = "Unable to read....";
 
   clog << "Error message : " << str << endl;
}

當上面的程式碼被編譯和執行時,它會產生下列結果:

Error message : Unable to read....

通過這些小例項,我們無法區分 cout、cerr 和 clog 的差異,但在編寫和執行大型程式時,它們之間的差異就變得非常明顯。所以良好的程式設計實踐告訴我們,使用 cerr 流來顯示錯誤訊息,而其他的日誌訊息則使用 clog 流來輸出。

C++ 指標

學習 C++ 的指標既簡單又有趣。通過指標,可以簡化一些 C++ 程式設計任務的執行,還有一些任務,如動態記憶體分配,沒有指標是無法執行的。所以,想要成為一名優秀的 C++ 程式設計師,學習指標是很有必要的。

每一個變數都有一個記憶體位置,每一個記憶體位置都定義了可使用連字號(&)運算子訪問的地址,它表示了在記憶體中的一個地址。請看下面的例項,它將輸出定義的變數地址:

例項

#include <iostream>
 
using namespace std;
 
int main ()
{
   int  var1;
   char var2[10];
 
   cout << "var1 變數的地址:";
   cout << &var1 << endl;
 
   cout << "var2 變數的地址:";
   cout << &var2 << endl;
 
   return 0;
}

當上面的程式碼被編譯和執行時,它會產生下列結果:

var1 變數的地址:0xbfebd5c0
var2 變數的地址:0xbfebd5b6

通過上面的例項,我們瞭解了什麼是記憶體地址以及如何訪問它。接下來讓我們看看什麼是指標。

什麼是指標?

指標是一個變數,其值為另一個變數的地址,即,記憶體位置的直接地址。就像其他變數或常量一樣,必須在使用指標儲存其他變數地址之前,對其進行宣告。指標變數宣告的一般形式為:

type *var-name;

在這裡,type 是指標的基型別,它必須是一個有效的 C++ 資料型別,var-name 是指標變數的名稱。用來宣告指標的星號 * 與乘法中使用的星號是相同的。但是,在這個語句中,星號是用來指定一個變數是指標。以下是有效的指標宣告:

int *ip; /* 一個整型的指標 */
double *dp; /* 一個 double 型的指標 */
float *fp; /* 一個浮點型的指標 */
char *ch; /* 一個字元型的指標 */

所有指標的值的實際資料型別,不管是整型、浮點型、字元型,還是其他的資料型別,都是一樣的,都是一個代表記憶體地址的長的十六進位制數。不同資料型別的指標之間唯一的不同是,指標所指向的變數或常量的資料型別不同。

C++ 中使用指標

使用指標時會頻繁進行以下幾個操作:定義一個指標變數、把變數地址賦值給指標、訪問指標變數中可用地址的值。這些是通過使用一元運算子 *來返回位於運算元所指定地址的變數的值。下面的例項涉及到了這些操作:

例項

#include <iostream>
 
using namespace std;
 
int main ()
{
   int  var = 20;   // 實際變數的宣告
   int  *ip;        // 指標變數的宣告
 
   ip = &var;       // 在指標變數中儲存 var 的地址
 
   cout << "Value of var variable: ";
   cout << var << endl;
 
   // 輸出在指標變數中儲存的地址
   cout << "Address stored in ip variable: ";
   cout << ip << endl;
 
   // 訪問指標中地址的值
   cout << "Value of *ip variable: ";
   cout << *ip << endl;
 
   return 0;
}

當上面的程式碼被編譯和執行時,它會產生下列結果:

Value of var variable: 20
Address stored in ip variable: 0xbfc601ac
Value of *ip variable: 20

C++ 引用

引用變數是一個別名,也就是說,它是某個已存在變數的另一個名字。一旦把引用初始化為某個變數,就可以使用該引用名稱或變數名稱來指向變數。

C++ 引用 vs 指標

引用很容易與指標混淆,它們之間有三個主要的不同:

  • 不存在空引用。引用必須連線到一塊合法的記憶體。

  • 一旦引用被初始化為一個物件,就不能被指向到另一個物件。指標可以在任何時候指向到另一個物件。

  • 引用必須在建立時被初始化。指標可以在任何時間被初始化。

C++ 中建立引用

試想變數名稱是變數附屬在記憶體位置中的標籤,可以把引用當成是變數附屬在記憶體位置中的第二個標籤。因此,可以通過原始變數名稱或引用來訪問變數的內容。例如:

int i = 17;

我們可以為 i 宣告引用變數,如下所示:

int& r = i;
double& s = d;

在這些宣告中,& 讀作引用。因此,第一個宣告可以讀作 "r 是一個初始化為 i 的整型引用",第二個宣告可以讀作 "s 是一個初始化為 d 的 double 型引用"。下面的例項使用了 int 和 double 引用:

例項

#include <iostream>
 
using namespace std;
 
int main ()
{
   // 宣告簡單的變數
   int    i;
   double d;
 
   // 宣告引用變數
   int&    r = i;
   double& s = d;
   
   i = 5;
   cout << "Value of i : " << i << endl;
   cout << "Value of i reference : " << r  << endl;
 
   d = 11.7;
   cout << "Value of d : " << d << endl;
   cout << "Value of d reference : " << s  << endl;
   
   return 0;
}

當上面的程式碼被編譯和執行時,它會產生下列結果:

Value of i : 5
Value of i reference : 5
Value of d : 11.7
Value of d reference : 11.7

引用通常用於函式引數列表和函式返回值。下面列出了 C++ 程式設計師必須清楚的兩個與 C++ 引用相關的重要概念:

概念描述

把引用作為引數

C++ 支援把引用作為引數傳給函式,這比傳一般的引數更安全。

把引用作為返回值

可以從 C++ 函式中返回引用,就像返回其他資料型別一樣。

四、 C++ 類與物件初探:繼承和過載

 C++ 類 & 物件

C++ 在 C 語言的基礎上增加了物件導向程式設計,C++ 支援物件導向程式設計。類是 C++ 的核心特性,通常被稱為使用者定義的型別。

類用於指定物件的形式,它包含了資料表示法和用於處理資料的方法。類中的資料和方法稱為類的成員。函式在一個類中被稱為類的成員。

C++ 類定義

定義一個類,本質上是定義一個資料型別的藍圖。這實際上並沒有定義任何資料,但它定義了類的名稱意味著什麼,也就是說,它定義了類的物件包括了什麼,以及可以在這個物件上執行哪些操作。

類定義是以關鍵字 class 開頭,後跟類的名稱。類的主體是包含在一對花括號中。類定義後必須跟著一個分號或一個宣告列表。例如,我們使用關鍵字 class 定義 Box 資料型別,如下所示:

class Box
{
   public:
      double length;   // 盒子的長度
      double breadth;  // 盒子的寬度
      double height;   // 盒子的高度
};

關鍵字 public 確定了類成員的訪問屬性。在類物件作用域內,公共成員在類的外部是可訪問的。也可以指定類的成員為 private 或 protected。

定義 C++ 物件

類提供了物件的藍圖,所以基本上,物件是根據類來建立的。宣告類的物件,就像宣告基本型別的變數一樣。下面的語句宣告瞭類 Box 的兩個物件:

Box Box1; // 宣告 Box1,型別為 Box Box Box2; // 宣告 Box2,型別為 Box
物件 Box1 和 Box2 都有它們各自的資料成員。

訪問資料成員

類的物件的公共資料成員可以使用直接成員訪問運算子 (.) 來訪問。為了更好地理解這些概念,讓我們嘗試一下下面的例項:

例項

#include <iostream>
 
using namespace std;
 
class Box
{
   public:
      double length;   // 長度
      double breadth;  // 寬度
      double height;   // 高度
};
 
int main( )
{
   Box Box1;        // 宣告 Box1,型別為 Box
   Box Box2;        // 宣告 Box2,型別為 Box
   double volume = 0.0;     // 用於儲存體積
 
   // box 1 詳述
   Box1.height = 5.0; 
   Box1.length = 6.0; 
   Box1.breadth = 7.0;
 
   // box 2 詳述
   Box2.height = 10.0;
   Box2.length = 12.0;
   Box2.breadth = 13.0;
 
   // box 1 的體積
   volume = Box1.height * Box1.length * Box1.breadth;
   cout << "Box1 的體積:" << volume <<endl;
 
   // box 2 的體積
   volume = Box2.height * Box2.length * Box2.breadth;
   cout << "Box2 的體積:" << volume <<endl;
   return 0;
}

當上面的程式碼被編譯和執行時,它會產生下列結果:

Box1 的體積:210
Box2 的體積:1560

需要注意的是,私有的成員和受保護的成員不能使用直接成員訪問運算子 (.) 來直接訪問。

C++ 繼承

物件導向程式設計中最重要的一個概念是繼承。繼承允許我們依據另一個類來定義一個類,這使得建立和維護一個應用程式變得更容易。這樣做,也達到了重用程式碼功能和提高執行時間的效果。

當建立一個類時,您不需要重新編寫新的資料成員和成員函式,只需指定新建的類繼承了一個已有的類的成員即可。這個已有的類稱為基類,新建的類稱為派生類。

繼承代表了 is a 關係。例如,哺乳動物是動物,狗是哺乳動物,因此,狗是動物,等等。

基類 & 派生類

一個類可以派生自多個類,這意味著,它可以從多個基類繼承資料和函式。定義一個派生類,我們使用一個類派生列表來指定基類。類派生列表以一個或多個基類命名,形式如下:

class derived-class: access-specifier base-class

其中,訪問修飾符 access-specifier 是 public、protected 或 private 其中的一個,base-class 是之前定義過的某個類的名稱。如果未使用訪問修飾符 access-specifier,則預設為 private。

假設有一個基類 Shape,Rectangle 是它的派生類,如下所示:

例項

#include <iostream>
 
using namespace std;
 
// 基類
class Shape 
{
   public:
      void setWidth(int w)
{
         width = w;
      }
      void setHeight(int h)
{
         height = h;
      }
   protected:
      int width;
      int height;
};
 
// 派生類
class Rectangle: public Shape
{
   public:
      int getArea()
{ 
         return (width * height); 
      }
};
 
int main(void)
{
   Rectangle Rect;
 
   Rect.setWidth(5);
   Rect.setHeight(7);
 
   // 輸出物件的面積
   cout << "Total area: " << Rect.getArea() << endl;
 
   return 0;
}

當上面的程式碼被編譯和執行時,它會產生下列結果:

Total area: 35

訪問控制和繼承

派生類可以訪問基類中所有的非私有成員。因此基類成員如果不想被派生類的成員函式訪問,則應在基類中宣告為 private。

我們可以根據訪問許可權總結出不同的訪問型別,如下所示:

訪問publicprotectedprivate

同一個類

yes

yes

yes

派生類

yes

yes

no

外部的類

yes

no

no

一個派生類繼承了所有的基類方法,但下列情況除外:

  • 基類的建構函式、解構函式和拷貝建構函式。

  • 基類的過載運算子。

  • 基類的友元函式。

繼承型別

當一個類派生自基類,該基類可以被繼承為 public、protected 或 private 幾種型別。繼承型別是通過上面講解的訪問修飾符 access-specifier 來指定的。

我們幾乎不使用 protected 或 private 繼承,通常使用 public 繼承。當使用不同型別的繼承時,遵循以下幾個規則:

  • 公有繼承(public):當一個類派生自公有基類時,基類的公有成員也是派生類的公有成員,基類的保護成員也是派生類的保護成員,基類的私有成員不能直接被派生類訪問,但是可以通過呼叫基類的公有和保護成員來訪問。

  • 保護繼承(protected):當一個類派生自保護基類時,基類的公有和保護成員將成為派生類的保護成員。

  • 私有繼承(private):當一個類派生自私有基類時,基類的公有和保護成員將成為派生類的私有成員。

多繼承

多繼承即一個子類可以有多個父類,它繼承了多個父類的特性。

C++ 類可以從多個類繼承成員,語法如下:

class <派生類名>:<繼承方式1><基類名1>,<繼承方式2><基類名2>,…
{
<派生類類體>
};

其中,訪問修飾符繼承方式是 public、protected 或 private 其中的一個,用來修飾每個基類,各個基類之間用逗號分隔,如上所示。現在讓我們一起看看下面的例項:

例項

#include <iostream>
 
using namespace std;
 
// 基類 Shape
class Shape 
{
   public:
      void setWidth(int w)
{
         width = w;
      }
      void setHeight(int h)
{
         height = h;
      }
   protected:
      int width;
      int height;
};
 
// 基類 PaintCost
class PaintCost 
{
   public:
      int getCost(int area)
{
         return area * 70;
      }
};
 
// 派生類
class Rectangle: public Shape, public PaintCost
{
   public:
      int getArea()
{ 
         return (width * height); 
      }
};
 
int main(void)
{
   Rectangle Rect;
   int area;
 
   Rect.setWidth(5);
   Rect.setHeight(7);
 
   area = Rect.getArea();
   
   // 輸出物件的面積
   cout << "Total area: " << Rect.getArea() << endl;
 
   // 輸出總花費
   cout << "Total paint cost: $" << Rect.getCost(area) << endl;
 
   return 0;
}

當上面的程式碼被編譯和執行時,它會產生下列結果:

Total area: 35
Total paint cost: $2450

C++ 過載運算子和過載函式

C++ 允許在同一作用域中的某個函式運算子指定多個定義,分別稱為函式過載和運算子過載。

過載宣告是指一個與之前已經在該作用域內宣告過的函式或方法具有相同名稱的宣告,但是它們的引數列表和定義(實現)不相同。

當您呼叫一個過載函式或過載運算子時,編譯器通過把您所使用的引數型別與定義中的引數型別進行比較,決定選用最合適的定義。選擇最合適的過載函式或過載運算子的過程,稱為過載決策。

C++ 中的函式過載

在同一個作用域內,可以宣告幾個功能類似的同名函式,但是這些同名函式的形式引數(指引數的個數、型別或者順序)必須不同。您不能僅通過返回型別的不同來過載函式。

下面的例項中,同名函式 print() 被用於輸出不同的資料型別:

例項

#include <iostream>
using namespace std;
 
class printData
{
   public:
      void print(int i) {
        cout << "整數為: " << i << endl;
      }
 
      void print(double  f) {
        cout << "浮點數為: " << f << endl;
      }
 
      void print(char c[]) {
        cout << "字串為: " << c << endl;
      }
};
 
int main(void)
{
   printData pd;
 
   // 輸出整數
   pd.print(5);
   // 輸出浮點數
   pd.print(500.263);
   // 輸出字串
   char c[] = "Hello C++";
   pd.print(c);
 
   return 0;
}

當上面的程式碼被編譯和執行時,它會產生下列結果:

整數為: 5
浮點數為: 500.263
字串為: Hello C++

C++ 中的運算子過載

您可以重定義或過載大部分 C++ 內建的運算子。這樣,您就能使用自定義型別的運算子。

過載的運算子是帶有特殊名稱的函式,函式名是由關鍵字 operator 和其後要過載的運算子符號構成的。與其他函式一樣,過載運算子有一個返回型別和一個引數列表。

Box operator+(const Box&);

宣告加法運算子用於把兩個 Box 物件相加,返回最終的 Box 物件。大多數的過載運算子可被定義為普通的非成員函式或者被定義為類成員函式。如果我們定義上面的函式為類的非成員函式,那麼我們需要為每次操作傳遞兩個引數,如下所示:

Box operator+(const Box&, const Box&);

下面的例項使用成員函式演示了運算子過載的概念。在這裡,物件作為引數進行傳遞,物件的屬性使用 this 運算子進行訪問,如下所示:

例項

#include <iostream>
using namespace std;
 
class Box
{
   public:
 
      double getVolume(void)
{
         return length * breadth * height;
      }
      void setLength( double len )
{
          length = len;
      }
 
      void setBreadth( double bre )
{
          breadth = bre;
      }
 
      void setHeight( double hei )
{
          height = hei;
      }
      // 過載 + 運算子,用於把兩個 Box 物件相加
      Box operator+(const Box& b)
      {
         Box box;
         box.length = this->length + b.length;
         box.breadth = this->breadth + b.breadth;
         box.height = this->height + b.height;
         return box;
      }
   private:
      double length;      // 長度
      double breadth;     // 寬度
      double height;      // 高度
};
// 程式的主函式
int main( )
{
   Box Box1;                // 宣告 Box1,型別為 Box
   Box Box2;                // 宣告 Box2,型別為 Box
   Box Box3;                // 宣告 Box3,型別為 Box
   double volume = 0.0;     // 把體積儲存在該變數中
 
   // Box1 詳述
   Box1.setLength(6.0); 
   Box1.setBreadth(7.0); 
   Box1.setHeight(5.0);
 
   // Box2 詳述
   Box2.setLength(12.0); 
   Box2.setBreadth(13.0); 
   Box2.setHeight(10.0);
 
   // Box1 的體積
   volume = Box1.getVolume();
   cout << "Volume of Box1 : " << volume <<endl;
 
   // Box2 的體積
   volume = Box2.getVolume();
   cout << "Volume of Box2 : " << volume <<endl;
 
   // 把兩個物件相加,得到 Box3
   Box3 = Box1 + Box2;
 
   // Box3 的體積
   volume = Box3.getVolume();
   cout << "Volume of Box3 : " << volume <<endl;
 
   return 0;
}

當上面的程式碼被編譯和執行時,它會產生下列結果:

Volume of Box1 : 210
Volume of Box2 : 1560
Volume of Box3 : 5400

五 、C++進階 多型和資料抽象

C++ 多型

多型按字面的意思就是多種形態。當類之間存在層次結構,並且類之間是通過繼承關聯時,就會用到多型。

C++ 多型意味著呼叫成員函式時,會根據呼叫函式的物件的型別來執行不同的函式。

下面的例項中,基類 Shape 被派生為兩個類,如下所示:

例項

#include <iostream> 
using namespace std;
 
class Shape {
   protected:
      int width, height;
   public:
      Shape( int a=0, int b=0)
      {
         width = a;
         height = b;
      }
      int area()
{
         cout << "Parent class area :" <<endl;
         return 0;
      }
};
class Rectangle: public Shape{
   public:
      Rectangle( int a=0, int b=0):Shape(a, b) { }
      int area ()
{ 
         cout << "Rectangle class area :" <<endl;
         return (width * height); 
      }
};
class Triangle: public Shape{
   public:
      Triangle( int a=0, int b=0):Shape(a, b) { }
      int area ()
{ 
         cout << "Triangle class area :" <<endl;
         return (width * height / 2); 
      }
};
// 程式的主函式
int main( )
{
   Shape *shape;
   Rectangle rec(10,7);
   Triangle  tri(10,5);
 
   // 儲存矩形的地址
   shape = &rec;
   // 呼叫矩形的求面積函式 area
   shape->area();
 
   // 儲存三角形的地址
   shape = &tri;
   // 呼叫三角形的求面積函式 area
   shape->area();
   
   return 0;
}

當上面的程式碼被編譯和執行時,它會產生下列結果:

Parent class area
Parent class area

導致錯誤輸出的原因是,呼叫函式 area() 被編譯器設定為基類中的版本,這就是所謂的靜態多型,或靜態連結 - 函式呼叫在程式執行前就準備好了。有時候這也被稱為早繫結,因為 area() 函式在程式編譯期間就已經設定好了。

但現在,讓我們對程式稍作修改,在 Shape 類中,area() 的宣告前放置關鍵字 virtual,如下所示:

class Shape {
   protected:
      int width, height;
   public:
      Shape( int a=0, int b=0)
      {
         width = a;
         height = b;
      }
      virtual int area()
{
         cout << "Parent class area :" <<endl;
         return 0;
      }
};

修改後,當編譯和執行前面的例項程式碼時,它會產生以下結果:

Rectangle class area
Triangle class area

此時,編譯器看的是指標的內容,而不是它的型別。因此,由於 tri 和 rec 類的物件的地址儲存在 *shape 中,所以會呼叫各自的 area() 函式。

正如大家所看到的,每個子類都有一個函式 area() 的獨立實現。這就是多型的一般使用方式。有了多型,就可以有多個不同的類,都帶有同一個名稱但具有不同實現的函式,函式的引數甚至可以是相同的。

虛擬函式

虛擬函式 是在基類中使用關鍵字 virtual 宣告的函式。在派生類中重新定義基類中定義的虛擬函式時,會告訴編譯器不要靜態連結到該函式。

我們想要的是在程式中任意點可以根據所呼叫的物件型別來選擇呼叫的函式,這種操作被稱為動態連結,或後期繫結。

純虛擬函式

大家可能想要在基類中定義虛擬函式,以便在派生類中重新定義該函式更好地適用於物件,但是大家在基類中又不能對虛擬函式給出有意義的實現,這個時候就會用到純虛擬函式。

我們可以把基類中的虛擬函式 area() 改寫如下:

class Shape {
   protected:
      int width, height;
   public:
      Shape( int a=0, int b=0)
      {
         width = a;
         height = b;
      }
      // pure virtual function
      virtual int area() = 0;
};

= 0 告訴編譯器,函式沒有主體,上面的虛擬函式是純虛擬函式。

C++ 資料抽象

資料抽象是指,只向外界提供關鍵資訊,並隱藏其後臺的實現細節,即只表現必要的資訊而不呈現細節。

資料抽象是一種依賴於介面和實現分離的程式設計(設計)技術。

讓我們舉一個現實生活中的真例項子,比如一臺電視機,可以開啟和關閉、切換頻道、調整音量、新增外部元件(如喇叭、錄影機、DVD 播放器),但是我們不知道它的內部實現細節,也就是說,我們並不知道它是如何通過纜線接收訊號,如何轉換訊號,並最終顯示在螢幕上。

因此,我們可以說電視把它的內部實現和外部介面分離開了,我們無需知道它的內部實現原理,直接通過它的外部介面(比如電源按鈕、遙控器、聲量控制器)就可以操控電視。

現在,讓我們言歸正傳,就 C++ 程式設計而言,C++ 類為資料抽象提供了可能。它們向外界提供了大量用於操作物件資料的公共方法,也就是說,外界實際上並不清楚類的內部實現。

例如,程式可以呼叫 sort() 函式,而不需要知道函式中排序資料所用到的演算法。實際上,函式排序的底層實現會因庫的版本不同而有所差異,只要介面不變,函式呼叫就可以照常工作。

在 C++ 中,我們使用類來定義我們自己的抽象資料型別(ADT)。可以使用類 iostream 的 cout 物件來輸出資料到標準輸出,如下所示:

例項

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

在這裡,暫時不需要理解 cout 是如何在使用者的螢幕上顯示文字。只需要知道公共介面即可,cout 的底層實現可以自由改變。

訪問標籤強制抽象

在 C++ 中,我們使用訪問標籤來定義類的抽象介面。一個類可以包含零個或多個訪問標籤:

  • 使用公共標籤定義的成員都可以訪問該程式的所有部分。一個型別的資料抽象檢視是由它的公共成員來定義的。

  • 使用私有標籤定義的成員無法訪問到使用類的程式碼。私有部分對使用型別的程式碼隱藏了實現細節。

訪問標籤出現的頻率沒有限制。每個訪問標籤指定了緊隨其後的成員定義的訪問級別。指定的訪問級別會一直有效,直到遇到下一個訪問標籤或者遇到類主體的關閉右括號為止。

資料抽象的好處

資料抽象有兩個重要的優勢:

  • 類的內部受到保護,不會因無意的使用者級錯誤導致物件狀態受損。

  • 類實現可能隨著時間的推移而發生變化,以便應對不斷變化的需求,或者應對那些要求不改變使用者級程式碼的錯誤報告。

如果只在類的私有部分定義資料成員,編寫該類的作者就可以隨意更改資料。如果實現發生改變,則只需要檢查類的程式碼,看看這個改變會導致哪些影響。

如果資料是公有的,則任何直接訪問舊錶示形式的資料成員的函式都可能受到影響。

資料抽象的例項

C++ 程式中,任何帶有公有和私有成員的類都可以作為資料抽象的例項。請看下面的例項:

例項

#include <iostream>
using namespace std;
 
class Adder{
   public:
      // 建構函式
      Adder(int i = 0)
      {
        total = i;
      }
      // 對外的介面
      void addNum(int number)
{
          total += number;
      }
      // 對外的介面
      int getTotal()
{
          return total;
      };
   private:
      // 對外隱藏的資料
      int total;
};
int main( )
{
   Adder a;
   
   a.addNum(10);
   a.addNum(20);
   a.addNum(30);
 
   cout << "Total " << a.getTotal() <<endl;
   return 0;
}

當上面的程式碼被編譯和執行時,它會產生下列結果:

Total 60

上面的類把數字相加,並返回總和。公有成員 addNum 和 getTotal 是對外的介面,使用者需要知道它們以便使用類。私有成員 total 是使用者不需要了解的,但又是類能正常工作所必需的。

C++ 資料封裝

所有的 C++ 程式都有以下兩個基本要素:

  • 程式語句(程式碼):這是程式中執行動作的部分,它們被稱為函式。

  • 程式資料:資料是程式的資訊,會受到程式函式的影響。

封裝是物件導向程式設計中的把資料和運算元據的函式繫結在一起的一個概念,這樣能避免受到外界的干擾和誤用,從而確保了安全。資料封裝引申出了另一個重要的 OOP 概念,即資料隱藏。

資料封裝是一種把資料和運算元據的函式捆綁在一起的機制,資料抽象是一種僅向使用者暴露介面而把具體的實現細節隱藏起來的機制。

C++ 通過建立類來支援封裝和資料隱藏(public、protected、private)。我們已經知道,類包含私有成員(private)、保護成員(protected)和公有成員(public)成員。預設情況下,在類中定義的所有專案都是私有的。例如:

class Box
{
   public:
      double getVolume(void)
      {
         return length * breadth * height;
      }
   private:
      double length;      // 長度
      double breadth;     // 寬度
      double height;      // 高度
};

變數 length、breadth 和 height 都是私有的(private)。這意味著它們只能被 Box 類中的其他成員訪問,而不能被程式中其他部分訪問。這是實現封裝的一種方式。

為了使類中的成員變成公有的(即,程式中的其他部分也能訪問),必須在這些成員前使用 public 關鍵字進行宣告。所有定義在 public 識別符號後邊的變數或函式可以被程式中所有其他的函式訪問。

把一個類定義為另一個類的友元類,會暴露實現細節,從而降低了封裝性。理想的做法是儘可能地對外隱藏每個類的實現細節。

資料封裝的例項

C++ 程式中,任何帶有公有和私有成員的類都可以作為資料封裝和資料抽象的例項。請看下面的例項:

例項

#include <iostream>
using namespace std;
 
class Adder{
   public:
      // 建構函式
      Adder(int i = 0)
      {
        total = i;
      }
      // 對外的介面
      void addNum(int number)
{
          total += number;
      }
      // 對外的介面
      int getTotal()
{
          return total;
      };
   private:
      // 對外隱藏的資料
      int total;
};
int main( )
{
   Adder a;
   
   a.addNum(10);
   a.addNum(20);
   a.addNum(30);
 
   cout << "Total " << a.getTotal() <<endl;
   return 0;
}

當上面的程式碼被編譯和執行時,它會產生下列結果:

Total 60

上面的類把數字相加,並返回總和。公有成員 addNum 和 getTotal 是對外的介面,使用者需要知道它們以便使用類。私有成員 total 是對外隱藏的,使用者不需要了解它,但它又是類能正常工作所必需的。

六、c++進階 模板和stl入門

C++ 模板

模板是泛型程式設計的基礎,泛型程式設計即以一種獨立於任何特定型別的方式編寫程式碼。

模板是建立泛型類或函式的藍圖或公式。庫容器,比如迭代器和演算法,都是泛型程式設計的例子,它們都使用了模板的概念。

每個容器都有一個單一的定義,比如 向量,我們可以定義許多不同型別的向量,比如 vector <int> 或 vector <string>。

您可以使用模板來定義函式和類,接下來讓我們一起來看看如何使用。

函式模板

模板函式定義的一般形式如下所示:

template <class type> ret-type func-name(parameter list) 
{
 // 函式的主體 
 }

在這裡,type 是函式所使用的資料型別的佔位符名稱。這個名稱可以在函式定義中使用。

下面是函式模板的例項,返回兩個數中的最大值:

例項

#include <iostream>
#include <string>
 
using namespace std;
 
template <typename T>
inline T const& Max (T const& a, T const& b) 
{ 
    return a < b ? b:a; 
} 
int main ()
{
 
    int i = 39;
    int j = 20;
    cout << "Max(i, j): " << Max(i, j) << endl; 
 
    double f1 = 13.5; 
    double f2 = 20.7; 
    cout << "Max(f1, f2): " << Max(f1, f2) << endl; 
 
    string s1 = "Hello"; 
    string s2 = "World"; 
    cout << "Max(s1, s2): " << Max(s1, s2) << endl; 
 
   return 0;
}

當上面的程式碼被編譯和執行時,它會產生下列結果:

Max(i, j): 39
Max(f1, f2): 20.7
Max(s1, s2): World類别範本

正如我們定義函式模板一樣,我們也可以定義類别範本。泛型類宣告的一般形式如下所示:

template <class type> class class-name {
.
.
.
}

在這裡,type 是佔位符型別名稱,可以在類被例項化的時候進行指定。您可以使用一個逗號分隔的列表來定義多個泛型資料型別。

下面的例項定義了類 Stack<>,並實現了泛型方法來對元素進行入棧出棧操作:

例項

#include <iostream>
#include <vector>
#include <cstdlib>
#include <string>
#include <stdexcept>
 
using namespace std;
 
template <class T>
class Stack { 
  private: 
    vector<T> elems;     // 元素 
 
  public: 
    void push(T const&);  // 入棧
    void pop();               // 出棧
    T top() const;            // 返回棧頂元素
    bool empty() const{       // 如果為空則返回真。
        return elems.empty(); 
    } 
}; 
 
template <class T>
void Stack<T>::push (T const& elem) 
{ 
    // 追加傳入元素的副本
    elems.push_back(elem);    
} 
 
template <class T>
void Stack<T>::pop () 
{ 
    if (elems.empty()) { 
        throw out_of_range("Stack<>::pop(): empty stack"); 
    }
    // 刪除最後一個元素
    elems.pop_back();         
} 
 
template <class T>
T Stack<T>::top () const 
{ 
    if (elems.empty()) { 
        throw out_of_range("Stack<>::top(): empty stack"); 
    }
    // 返回最後一個元素的副本 
    return elems.back();      
} 
 
int main() 
{ 
    try { 
        Stack<int>         intStack;  // int 型別的棧 
        Stack<string> stringStack;    // string 型別的棧 
 
        // 操作 int 型別的棧 
        intStack.push(7); 
        cout << intStack.top() <<endl; 
 
        // 操作 string 型別的棧 
        stringStack.push("hello"); 
        cout << stringStack.top() << std::endl; 
        stringStack.pop(); 
        stringStack.pop(); 
    } 
    catch (exception const& ex) { 
        cerr << "Exception: " << ex.what() <<endl; 
        return -1;
    } 
}

當上面的程式碼被編譯和執行時,它會產生下列結果:

7
hello
Exception: Stack<>::pop(): empty stack

C++ STL 入門

上面我們已經瞭解了 C++ 模板的概念。C++ STL(標準模板庫)是一套功能強大的 C++ 模板類,提供了通用的模板類和函式,這些模板類和函式可以實現多種流行和常用的演算法和資料結構,如向量、連結串列、佇列、棧。

C++ 標準模板庫的核心包括以下三個元件:

元件

描述 

容器(Containers)

容器是用來管理某一類物件的集合。C++ 提供了各種不同型別的容器,比如 deque、list、vector、map 等。

演算法(Algorithms)

演算法作用於容器。它們提供了執行各種操作的方式,包括對容器內容執行初始化、排序、搜尋和轉換等操作。

迭代器(iterators)

迭代器用於遍歷物件集合的元素。這些集合可能是容器,也可能是容器的子集。

這三個元件都帶有豐富的預定義函式,幫助我們通過簡單的方式處理複雜的任務。

下面的程式演示了向量容器(一個 C++ 標準的模板),它與陣列十分相似,唯一不同的是,向量在需要擴充套件大小的時候,會自動處理它自己的儲存需求:

例項

#include <iostream>
#include <vector>
using namespace std;
 
int main()
{
   // 建立一個向量儲存 int
   vector<int> vec; 
   int i;
 
   // 顯示 vec 的原始大小
   cout << "vector size = " << vec.size() << endl;
 
   // 推入 5 個值到向量中
   for(i = 0; i < 5; i++){
      vec.push_back(i);
   }
 
   // 顯示 vec 擴充套件後的大小
   cout << "extended vector size = " << vec.size() << endl;
 
   // 訪問向量中的 5 個值
   for(i = 0; i < 5; i++){
      cout << "value of vec [" << i << "] = " << vec[i] << endl;
   }
 
   // 使用迭代器 iterator 訪問值
   vector<int>::iterator v = vec.begin();
   while( v != vec.end()) {
      cout << "value of v = " << *v << endl;
      v++;
   }
 
   return 0;
}

當上面的程式碼被編譯和執行時,它會產生下列結果:

vector size = 0
extended vector size = 5
value of vec [0] = 0
value of vec [1] = 1
value of vec [2] = 2
value of vec [3] = 3
value of vec [4] = 4
value of v = 0
value of v = 1
value of v = 2
value of v = 3
value of v = 4

關於上面例項中所使用的各種函式,有幾點要注意:

  • push_back( ) 成員函式在向量的末尾插入值,如果有必要會擴充套件向量的大小。

  • size( ) 函式顯示向量的大小。

  • begin( ) 函式返回一個指向向量開頭的迭代器。

  • end( ) 函式返回一個指向向量末尾的迭代器。

相關文章