C++系列之高級教程(一)

C++系列之高級教程(一)

[toc]

C++文件和流

iostream 標(biāo)準(zhǔn)庫提供了 cincout 方法分別用于從標(biāo)準(zhǔn)輸入讀取流和向標(biāo)準(zhǔn)輸出寫入流赤赊。

本教程介紹如何從文件讀取流和向文件寫入流灸拍。這就需要用到 C++ 中另一個標(biāo)準(zhǔn)庫 fstream,它定義了三個新的數(shù)據(jù)類型:

數(shù)據(jù)類型 描述
ofstream 該數(shù)據(jù)類型表示輸出文件流准谚,用于創(chuàng)建文件并向文件寫入信息逮走。
ifstream 該數(shù)據(jù)類型表示輸入文件流,用于從文件讀取信息。
fstream 該數(shù)據(jù)類型通常表示文件流,且同時具有 ofstream 和 ifstream 兩種功能数初,這意味著它可以創(chuàng)建文件,向文件寫入信息梗顺,從文件讀取信息泡孩。

要在 C++ 中進(jìn)行文件處理,必須在 C++ 源代碼文件中包含頭文件 <iostream> 和 <fstream>寺谤。

打開文件

在從文件讀取信息或者向文件寫入信息之前仑鸥,必須先打開文件。ofstreamfstream 對象都可以用來打開文件進(jìn)行寫操作变屁,如果只需要打開文件進(jìn)行讀操作眼俊,則使用 ifstream 對象。

下面是 open() 函數(shù)的標(biāo)準(zhǔn)語法粟关,open() 函數(shù)是 fstream泵琳、ifstream 和 ofstream 對象的一個成員。

void open(const char *filename, ios::openmode mode);

在這里,open() 成員函數(shù)的第一參數(shù)指定要打開的文件的名稱和位置获列,第二個參數(shù)定義文件被打開的模式谷市。

模式標(biāo)志 描述
ios::app 追加模式。所有寫入都追加到文件末尾击孩。
ios::ate 文件打開后定位到文件末尾迫悠。
ios::in 打開文件用于讀取。
ios::out 打開文件用于寫入巩梢。
ios::trunc 如果該文件已經(jīng)存在创泄,其內(nèi)容將在打開文件之前被截斷,即把文件長度設(shè)為 0括蝠。

您可以把以上兩種或兩種以上的模式結(jié)合使用鞠抑。例如,如果您想要以寫入模式打開文件忌警,并希望截斷文件搁拙,以防文件已存在,那么您可以使用下面的語法:

ofstream outfile;
outfile.open("file.dat", ios::out | ios::trunc );

類似地法绵,您如果想要打開一個文件用于讀寫箕速,可以使用下面的語法:

ifstream  afile;
afile.open("file.dat", ios::out | ios::in );

關(guān)閉文件

當(dāng) C++ 程序終止時,它會自動關(guān)閉刷新所有流朋譬,釋放所有分配的內(nèi)存盐茎,并關(guān)閉所有打開的文件。但程序員應(yīng)該養(yǎng)成一個好習(xí)慣徙赢,在程序終止前關(guān)閉所有打開的文件字柠。

下面是 close() 函數(shù)的標(biāo)準(zhǔn)語法,close() 函數(shù)是 fstream狡赐、ifstream 和 ofstream 對象的一個成員窑业。

void close();

寫入文件

在 C++ 編程中,我們使用流插入運算符( << )向文件寫入信息阴汇,就像使用該運算符輸出信息到屏幕上一樣数冬。唯一不同的是,在這里您使用的是 ofstreamfstream 對象搀庶,而不是 cout 對象拐纱。

讀取文件

在 C++ 編程中,我們使用流提取運算符( >> )從文件讀取信息哥倔,就像使用該運算符從鍵盤輸入信息一樣秸架。唯一不同的是,在這里您使用的是 ifstreamfstream 對象咆蒿,而不是 cin 對象东抹。

讀取&寫入實例

下面的 C++ 程序以讀寫模式打開一個文件蚂子。在向文件 afile.dat 寫入用戶輸入的信息之后,程序從文件讀取信息缭黔,并將其輸出到屏幕上:

#include <fstream>
#include <iostream>
using namespace std;
 
int main ()
{
    
   char data[100];
 
   // 以寫模式打開文件
   ofstream outfile;
   outfile.open("afile.dat");
 
   cout << "Writing to the file" << endl;
   cout << "Enter your name: "; 
   cin.getline(data, 100);
 
   // 向文件寫入用戶輸入的數(shù)據(jù)
   outfile << data << endl;
 
   cout << "Enter your age: "; 
   cin >> data;
   cin.ignore();
   
   // 再次向文件寫入用戶輸入的數(shù)據(jù)
   outfile << data << endl;
 
   // 關(guān)閉打開的文件
   outfile.close();
 
   // 以讀模式打開文件
   ifstream infile; 
   infile.open("afile.dat"); 
 
   cout << "Reading from the file" << endl; 
   infile >> data; 
 
   // 在屏幕上寫入數(shù)據(jù)
   cout << data << endl;
   
   // 再次從文件讀取數(shù)據(jù)食茎,并顯示它
   infile >> data; 
   cout << data << endl; 
 
   // 關(guān)閉打開的文件
   infile.close();
 
   return 0;
}
代碼運行結(jié)果:
$./a.out
Writing to the file
Enter your name: Zara
Enter your age: 9
Reading from the file
Zara
9

上面的實例中使用了 cin 對象的附加函數(shù),比如 getline()函數(shù)從外部讀取一行馏谨,ignore() 函數(shù)會忽略掉之前讀語句留下的多余字符别渔。

文件位置指針

istreamostream 都提供了用于重新定位文件位置指針的成員函數(shù)。這些成員函數(shù)包括關(guān)于 istream 的 seekg("seek get")和關(guān)于 ostream 的 seekp("seek put")惧互。

seekg 和 seekp 的參數(shù)通常是一個長整型哎媚。第二個參數(shù)可以用于指定查找方向。查找方向可以是 ios::beg(默認(rèn)的喊儡,從流的開頭開始定位)拨与,也可以是 ios::cur(從流的當(dāng)前位置開始定位),也可以是 ios::end(從流的末尾開始定位)艾猜。

文件位置指針是一個整數(shù)值买喧,指定了從文件的起始位置到指針?biāo)谖恢玫淖止?jié)數(shù)。下面是關(guān)于定位 "get" 文件位置指針的實例:

// 定位到 fileObject 的第 n 個字節(jié)(假設(shè)是 ios::beg)
fileObject.seekg( n );
 
// 把文件的讀指針從 fileObject 當(dāng)前位置向后移 n 個字節(jié)
fileObject.seekg( n, ios::cur );
 
// 把文件的讀指針從 fileObject 末尾往回移 n 個字節(jié)
fileObject.seekg( n, ios::end );
 
// 定位到 fileObject 的末尾
fileObject.seekg( 0, ios::end );

C++異常處理

異常是程序在執(zhí)行期間產(chǎn)生的問題箩朴。C++ 異常是指在程序運行時發(fā)生的特殊情況岗喉,比如嘗試除以零的操作秋度。

異常提供了一種轉(zhuǎn)移程序控制權(quán)的方式炸庞。C++ 異常處理涉及到三個關(guān)鍵字:try、catch荚斯、throw埠居。

  • throw: 當(dāng)問題出現(xiàn)時,程序會拋出一個異常事期。這是通過使用 throw 關(guān)鍵字來完成的滥壕。
  • catch: 在您想要處理問題的地方,通過異常處理程序捕獲異常兽泣。catch 關(guān)鍵字用于捕獲異常绎橘。
  • try: try 塊中的代碼標(biāo)識將被激活的特定異常。它后面通常跟著一個或多個 catch 塊唠倦。

如果有一個塊拋出一個異常称鳞,捕獲異常的方法會使用 trycatch 關(guān)鍵字。try 塊中放置可能拋出異常的代碼稠鼻,try 塊中的代碼被稱為保護(hù)代碼冈止。使用 try/catch 語句的語法如下所示:

try
{
   // 保護(hù)代碼
}catch( ExceptionName e1 )
{
   // catch 塊
}catch( ExceptionName e2 )
{
   // catch 塊
}catch( ExceptionName eN )
{
   // catch 塊
}

如果 try 塊在不同的情境下會拋出不同的異常,這個時候可以嘗試羅列多個 catch 語句候齿,用于捕獲不同類型的異常熙暴。

拋出異常

您可以使用 throw 語句在代碼塊中的任何地方拋出異常闺属。throw 語句的操作數(shù)可以是任意的表達(dá)式,表達(dá)式的結(jié)果的類型決定了拋出的異常的類型周霉。

以下是嘗試除以零時拋出異常的實例:

double division(int a, int b)
{
   if( b == 0 )
   {
      throw "Division by zero condition!";
   }
   return (a/b);
}

捕獲異常

catch 塊跟在 try 塊后面掂器,用于捕獲異常。您可以指定想要捕捉的異常類型俱箱,這是由 catch 關(guān)鍵字后的括號內(nèi)的異常聲明決定的唉匾。

try
{
   // 保護(hù)代碼
}catch( ExceptionName e )
{
  // 處理 ExceptionName 異常的代碼
}

上面的代碼會捕獲一個類型為 ExceptionName 的異常。如果您想讓 catch 塊能夠處理 try 塊拋出的任何類型的異常匠楚,則必須在異常聲明的括號內(nèi)使用省略號 ...巍膘,如下所示:

try
{
   // 保護(hù)代碼
}catch(...)
{
  // 能處理任何異常的代碼
}

下面是一個實例,拋出一個除以零的異常芋簿,并在 catch 塊中捕獲該異常峡懈。

#include <iostream>
using namespace std;
 
double division(int a, int b)
{
   if( b == 0 )
   {
      throw "Division by zero condition!";
   }
   return (a/b);
}
 
int main ()
{
   int x = 50;
   int y = 0;
   double z = 0;
 
   try {
     z = division(x, y);
     cout << z << endl;
   }catch (const char* msg) {
     cerr << msg << endl;
   }
 
   return 0;
}
//由于我們拋出了一個類型為 const char* 的異常,因此与斤,當(dāng)捕獲該異常時肪康,我們必須在 catch 塊中使用 const char*。當(dāng)上面的代碼被編譯和執(zhí)行時撩穿,它會產(chǎn)生下列結(jié)果:
代碼運行結(jié)果:
Division by zero condition!

C++標(biāo)準(zhǔn)的異常

C++ 提供了一系列標(biāo)準(zhǔn)的異常磷支,定義在 <exception> 中,我們可以在程序中使用這些標(biāo)準(zhǔn)的異常食寡。它們是以父子類層次結(jié)構(gòu)組織起來的雾狈,如下所示:

C++ 異常的層次結(jié)構(gòu)

下表是對上面層次結(jié)構(gòu)中出現(xiàn)的每個異常的說明:

異常 描述
std::exception 該異常是所有標(biāo)準(zhǔn) C++ 異常的父類。
std::bad_alloc 該異车种澹可以通過 new 拋出善榛。
std::bad_cast 該異常可以通過 dynamic_cast 拋出呻畸。
std::bad_exception 這在處理 C++ 程序中無法預(yù)期的異常時非常有用移盆。
std::bad_typeid 該異常可以通過 typeid 拋出伤为。
std::logic_error 理論上可以通過讀取代碼來檢測到的異常咒循。
std::domain_error 當(dāng)使用了一個無效的數(shù)學(xué)域時,會拋出該異常绞愚。
std::invalid_argument 當(dāng)使用了無效的參數(shù)時叙甸,會拋出該異常。
std::length_error 當(dāng)創(chuàng)建了太長的 std::string 時爽醋,會拋出該異常蚁署。
std::out_of_range 該異常可以通過方法拋出蚂四,例如 std::vector 和 std::bitset<>::operator光戈。
std::runtime_error 理論上不可以通過讀取代碼來檢測到的異常哪痰。
std::overflow_error 當(dāng)發(fā)生數(shù)學(xué)上溢時,會拋出該異常久妆。
std::range_error 當(dāng)嘗試存儲超出范圍的值時晌杰,會拋出該異常。
std::underflow_error 當(dāng)發(fā)生數(shù)學(xué)下溢時筷弦,會拋出該異常肋演。

定義新的異常

可以通過繼承和重載 exception 類來定義新的異常。下面的實例演示了如何使用 std::exception 類來實現(xiàn)自己的異常:

#include <iostream>
#include <exception>
using namespace std;
 
struct MyException : public exception
{
  const char * what () const throw ()
  {
    return "C++ Exception";
  }
};
 
int main()
{
  try
  {
    throw MyException();
  }
  catch(MyException& e)
  {
    std::cout << "MyException caught" << std::endl;
    std::cout << e.what() << std::endl;
  }
  catch(std::exception& e)
  {
    //其他的錯誤
  }
}
代碼運行結(jié)果:
MyException caught
C++ Exception

在這里烂琴,what() 是異常類提供的一個公共方法爹殊,它已被所有子異常類重載。這將返回異常產(chǎn)生的原因奸绷。

C++動態(tài)內(nèi)存

C++ 程序中的內(nèi)存分為兩個部分:

  • 棧:在函數(shù)內(nèi)部聲明的所有變量都將占用棧內(nèi)存梗夸。
  • 堆:這是程序中未使用的內(nèi)存,在程序運行時可用于動態(tài)分配內(nèi)存号醉。

很多時候無法提前預(yù)知需要多少內(nèi)存來存儲某個定義變量中的特定信息反症,所需內(nèi)存的大小需要在運行時才能確定。

在 C++ 中畔派,您可以使用特殊的運算符為給定類型的變量在運行時分配堆內(nèi)的內(nèi)存铅碍,這會返回所分配的空間地址。這種運算符即 new 運算符线椰。

如果不再需要動態(tài)分配的內(nèi)存空間胞谈,可以使用 delete 運算符,刪除之前由 new 運算符分配的內(nèi)存士嚎。

new和delete運算符

下面是使用 new 運算符來為任意的數(shù)據(jù)類型動態(tài)分配內(nèi)存的通用語法:

new data-type;

在這里呜魄,data-type 可以是包括數(shù)組在內(nèi)的任意內(nèi)置的數(shù)據(jù)類型悔叽,也可以是包括類或結(jié)構(gòu)在內(nèi)的用戶自定義的任何數(shù)據(jù)類型莱衩。讓我們先來看下內(nèi)置的數(shù)據(jù)類型。例如娇澎,我們可以定義一個指向 double 類型的指針笨蚁,然后請求內(nèi)存,該內(nèi)存在執(zhí)行時被分配趟庄。我們可以按照下面的語句使用 new 運算符來完成這點:

double* pvalue  = NULL; // 初始化為 null 的指針
pvalue  = new double;   // 為變量請求內(nèi)存

如果自由存儲區(qū)已被用完括细,可能無法成功分配內(nèi)存。所以建議檢查 new 運算符是否返回 NULL 指針戚啥,并采取以下適當(dāng)?shù)牟僮鳎?/p>

double* pvalue  = NULL;
if( !(pvalue  = new double ))
{
   cout << "Error: out of memory." <<endl;
   exit(1);
 
}

malloc() 函數(shù)在 C 語言中就出現(xiàn)了奋单,在 C++ 中仍然存在,但建議盡量不要使用 malloc() 函數(shù)猫十。new 與 malloc() 函數(shù)相比览濒,其主要的優(yōu)點是呆盖,new 不只是分配了內(nèi)存,它還創(chuàng)建了對象贷笛。

在任何時候应又,當(dāng)您覺得某個已經(jīng)動態(tài)分配內(nèi)存的變量不再需要使用時,您可以使用 delete 操作符釋放它所占用的內(nèi)存乏苦,如下所示:

delete pvalue; // 釋放 pvalue 所指向的內(nèi)存

下面的實例中使用了上面的概念株扛,演示了如何使用 new 和 delete 運算符:

#include <iostream>
using namespace std;
 
int main ()
{
   double* pvalue  = NULL; // 初始化為 null 的指針
   pvalue  = new double;   // 為變量請求內(nèi)存
 
   *pvalue = 29494.99;     // 在分配的地址存儲值
   cout << "Value of pvalue : " << *pvalue << endl;
 
   delete pvalue;         // 釋放內(nèi)存
 
   return 0;
}
代碼運行結(jié)果:
Value of pvalue : 29495

數(shù)組的動態(tài)內(nèi)存分配

假設(shè)我們要為一個字符數(shù)組(一個有 20 個字符的字符串)分配內(nèi)存,我們可以使用上面實例中的語法來為數(shù)組動態(tài)地分配內(nèi)存汇荐,如下所示:

char* pvalue  = NULL;   // 初始化為 null 的指針
pvalue  = new char[20]; // 為變量請求內(nèi)存

要刪除我們剛才創(chuàng)建的數(shù)組洞就,語句如下:

delete [] pvalue;        // 刪除 pvalue 所指向的數(shù)組

下面是 new 操作符的通用語法,可以為多維數(shù)組分配內(nèi)存掀淘,如下所示:

// 動態(tài)分配,數(shù)組長度為 m
int *array=new int [m];
 
//釋放內(nèi)存
delete [] array;

對象的動態(tài)內(nèi)存分配

對象與簡單的數(shù)據(jù)類型沒有什么不同奖磁。例如,請看下面的代碼繁疤,我們將使用一個對象數(shù)組來理清這一概念:

#include <iostream>
using namespace std;
 
class Box
{
   public:
      Box() { 
         cout << "調(diào)用構(gòu)造函數(shù)咖为!" <<endl; 
      }
      ~Box() { 
         cout << "調(diào)用析構(gòu)函數(shù)!" <<endl; 
      }
};
 
int main( )
{
   Box* myBoxArray = new Box[4];
 
   delete [] myBoxArray; // 刪除數(shù)組
   return 0;
}

如果要為一個包含四個 Box 對象的數(shù)組分配內(nèi)存稠腊,構(gòu)造函數(shù)將被調(diào)用 4 次躁染,同樣地,當(dāng)刪除這些對象時架忌,析構(gòu)函數(shù)也將被調(diào)用相同的次數(shù)(4次)吞彤。

當(dāng)上面的代碼被編譯和執(zhí)行時,它會產(chǎn)生下列結(jié)果:

調(diào)用構(gòu)造函數(shù)叹放!
調(diào)用構(gòu)造函數(shù)饰恕!
調(diào)用構(gòu)造函數(shù)!
調(diào)用構(gòu)造函數(shù)井仰!
調(diào)用析構(gòu)函數(shù)埋嵌!
調(diào)用析構(gòu)函數(shù)!
調(diào)用析構(gòu)函數(shù)俱恶!
調(diào)用析構(gòu)函數(shù)雹嗦!

C++命名空間

假設(shè)這樣一種情況,當(dāng)一個班上有兩個名叫 Zara 的學(xué)生時合是,為了明確區(qū)分它們了罪,我們在使用名字之外,不得不使用一些額外的信息聪全,比如他們的家庭住址泊藕,或者他們父母的名字等等。

同樣的情況也出現(xiàn)在 C++ 應(yīng)用程序中难礼。例如娃圆,您可能會寫一個名為 xyz() 的函數(shù)汽久,在另一個可用的庫中也存在一個相同的函數(shù) xyz()。這樣踊餐,編譯器就無法判斷您所使用的是哪一個 xyz() 函數(shù)景醇。

因此,引入了命名空間這個概念吝岭,專門用于解決上面的問題三痰,它可作為附加信息來區(qū)分不同庫中相同名稱的函數(shù)、類窜管、變量等散劫。使用了命名空間即定義了上下文。本質(zhì)上幕帆,命名空間就是定義了一個范圍获搏。

我們舉一個計算機(jī)系統(tǒng)中的例子,一個文件夾(目錄)中可以包含多個文件夾失乾,每個文件夾中不能有相同的文件名常熙,但不同文件夾中的文件可以重名。

img

定義命名空間

命名空間的定義使用關(guān)鍵字 namespace碱茁,后跟命名空間的名稱裸卫,如下所示:

namespace namespace_name {
   // 代碼聲明
}

為了調(diào)用帶有命名空間的函數(shù)或變量,需要在前面加上命名空間的名稱纽竣,如下所示:

name::code; // code 可以是變量或函數(shù)

讓我們來看看命名空間如何為變量或函數(shù)等實體定義范圍:

#include <iostream>
using namespace std;
 
// 第一個命名空間
namespace first_space{
   void func(){
      cout << "Inside first_space" << endl;
   }
}
// 第二個命名空間
namespace second_space{
   void func(){
      cout << "Inside second_space" << endl;
   }
}
int main ()
{
 
   // 調(diào)用第一個命名空間中的函數(shù)
   first_space::func();
   
   // 調(diào)用第二個命名空間中的函數(shù)
   second_space::func(); 
 
   return 0;
}
代碼運行結(jié)果:
Inside first_space
Inside second_space

using 指令

可以使用 using namespace 指令墓贿,這樣在使用命名空間時就可以不用在前面加上命名空間的名稱。這個指令會告訴編譯器蜓氨,后續(xù)的代碼將使用指定的命名空間中的名稱聋袋。

#include <iostream>
using namespace std;
 
// 第一個命名空間
namespace first_space{
   void func(){
      cout << "Inside first_space" << endl;
   }
}
// 第二個命名空間
namespace second_space{
   void func(){
      cout << "Inside second_space" << endl;
   }
}
using namespace first_space;
int main ()
{
 
   // 調(diào)用第一個命名空間中的函數(shù)
   func();
   
   return 0;
}
代碼運行結(jié)果:
Inside first_space

using 指令也可以用來指定命名空間中的特定項目。例如穴吹,如果您只打算使用 std 命名空間中的 cout 部分幽勒,您可以使用如下的語句:

using std::cout;

#include <iostream>
using std::cout;
 
int main ()
{
 
   cout << "std::endl is used with std!" << std::endl;
   
   return 0;
}
代碼運行結(jié)果:
std::endl is used with std!

using 指令引入的名稱遵循正常的范圍規(guī)則。名稱從使用 using 指令開始是可見的刀荒,直到該范圍結(jié)束代嗤。此時,在范圍以外定義的同名實體是隱藏的缠借。

不連續(xù)的命名空間

命名空間可以定義在幾個不同的部分中,因此命名空間是由幾個單獨定義的部分組成的宜猜。一個命名空間的各個組成部分可以分散在多個文件中泼返。

所以,如果命名空間中的某個組成部分需要請求定義在另一個文件中的名稱姨拥,則仍然需要聲明該名稱绅喉。下面的命名空間定義可以是定義一個新的命名空間渠鸽,也可以是為已有的命名空間增加新的元素:

namespace namespace_name {
   // 代碼聲明
}

嵌套的命名空間

命名空間可以嵌套,您可以在一個命名空間中定義另一個命名空間柴罐,如下所示:

namespace namespace_name1 {
   // 代碼聲明
   namespace namespace_name2 {
      // 代碼聲明
   }
}

您可以通過使用 :: 運算符來訪問嵌套的命名空間中的成員:

// 訪問 namespace_name2 中的成員
using namespace namespace_name1::namespace_name2;
 
// 訪問 namespace:name1 中的成員
using namespace namespace_name1;

在上面的語句中徽缚,如果使用的是 namespace_name1,那么在該范圍內(nèi) namespace_name2 中的元素也是可用的革屠,如下所示:

#include <iostream>
using namespace std;
 
// 第一個命名空間
namespace first_space{
   void func(){
      cout << "Inside first_space" << endl;
   }
   // 第二個命名空間
   namespace second_space{
      void func(){
         cout << "Inside second_space" << endl;
      }
   }
}
using namespace first_space::second_space;
int main ()
{
 
   // 調(diào)用第二個命名空間中的函數(shù)
   func();
   
   return 0;
}
代碼運行結(jié)果:
Inside second_space

C++模板

模板是泛型編程的基礎(chǔ)凿试,泛型編程即以一種獨立于任何特定類型的方式編寫代碼。

模板是創(chuàng)建泛型類或函數(shù)的藍(lán)圖或公式似芝。庫容器那婉,比如迭代器和算法,都是泛型編程的例子党瓮,它們都使用了模板的概念详炬。

每個容器都有一個單一的定義,比如 向量寞奸,我們可以定義許多不同類型的向量呛谜,比如 vector <int>vector <string>

您可以使用模板來定義函數(shù)和類枪萄,接下來讓我們一起來看看如何使用呻率。

函數(shù)模板

模板函數(shù)定義的一般形式如下所示:

template <typename type> ret-type func-name(parameter list)
{
   // 函數(shù)的主體
}

在這里,type 是函數(shù)所使用的數(shù)據(jù)類型的占位符名稱呻引。這個名稱可以在函數(shù)定義中使用礼仗。

下面是函數(shù)模板的實例,返回兩個數(shù)中的最大值:

#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;
}
代碼運行結(jié)果:
Max(i, j): 39
Max(f1, f2): 20.7
Max(s1, s2): World

類模板

正如我們定義函數(shù)模板一樣逻悠,我們也可以定義類模板元践。泛型類聲明的一般形式如下所示:

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

在這里,type 是占位符類型名稱童谒,可以在類被實例化的時候進(jìn)行指定单旁。您可以使用一個逗號分隔的列表來定義多個泛型數(shù)據(jù)類型。

下面的實例定義了類 Stack<>饥伊,并實現(xiàn)了泛型方法來對元素進(jìn)行入棧出棧操作:

#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;
    } 
}
代碼運行結(jié)果:
7
hello
Exception: Stack<>::pop(): empty stack
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市琅豆,隨后出現(xiàn)的幾起案子愉豺,更是在濱河造成了極大的恐慌,老刑警劉巖茫因,帶你破解...
    沈念sama閱讀 216,651評論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件蚪拦,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)驰贷,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,468評論 3 392
  • 文/潘曉璐 我一進(jìn)店門盛嘿,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人括袒,你說我怎么就攤上這事次兆。” “怎么了锹锰?”我有些...
    開封第一講書人閱讀 162,931評論 0 353
  • 文/不壞的土叔 我叫張陵芥炭,是天一觀的道長。 經(jīng)常有香客問我城须,道長蚤认,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,218評論 1 292
  • 正文 為了忘掉前任糕伐,我火速辦了婚禮砰琢,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘良瞧。我一直安慰自己陪汽,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 67,234評論 6 388
  • 文/花漫 我一把揭開白布褥蚯。 她就那樣靜靜地躺著挚冤,像睡著了一般。 火紅的嫁衣襯著肌膚如雪赞庶。 梳的紋絲不亂的頭發(fā)上训挡,一...
    開封第一講書人閱讀 51,198評論 1 299
  • 那天,我揣著相機(jī)與錄音歧强,去河邊找鬼澜薄。 笑死,一個胖子當(dāng)著我的面吹牛摊册,可吹牛的內(nèi)容都是我干的肤京。 我是一名探鬼主播,決...
    沈念sama閱讀 40,084評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼茅特,長吁一口氣:“原來是場噩夢啊……” “哼忘分!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起白修,我...
    開封第一講書人閱讀 38,926評論 0 274
  • 序言:老撾萬榮一對情侶失蹤妒峦,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后熬荆,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體舟山,經(jīng)...
    沈念sama閱讀 45,341評論 1 311
  • 正文 獨居荒郊野嶺守林人離奇死亡绸狐,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,563評論 2 333
  • 正文 我和宋清朗相戀三年卤恳,在試婚紗的時候發(fā)現(xiàn)自己被綠了累盗。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,731評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡突琳,死狀恐怖若债,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情拆融,我是刑警寧澤蠢琳,帶...
    沈念sama閱讀 35,430評論 5 343
  • 正文 年R本政府宣布,位于F島的核電站镜豹,受9級特大地震影響傲须,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜趟脂,卻給世界環(huán)境...
    茶點故事閱讀 41,036評論 3 326
  • 文/蒙蒙 一泰讽、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧昔期,春花似錦已卸、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,676評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至般贼,卻和暖如春愧哟,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背哼蛆。 一陣腳步聲響...
    開封第一講書人閱讀 32,829評論 1 269
  • 我被黑心中介騙來泰國打工蕊梧, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人人芽。 一個月前我還...
    沈念sama閱讀 47,743評論 2 368
  • 正文 我出身青樓望几,卻偏偏與公主長得像,于是被迫代替她去往敵國和親萤厅。 傳聞我的和親對象是個殘疾皇子橄抹,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,629評論 2 354

推薦閱讀更多精彩內(nèi)容

  • 4.高級主題 4.1 標(biāo)準(zhǔn)庫特殊設(shè)施 tuple類型希望將一些數(shù)據(jù)合成單一對象,但又不想麻煩地定義一個新數(shù)據(jù)結(jié)構(gòu)來...
    王偵閱讀 699評論 0 0
  • 重新系統(tǒng)學(xué)習(xí)下C++惕味;但是還是少了好多知識點楼誓;socket;unix名挥;stl疟羹;boost等; C++ 教程 | 菜...
    kakukeme閱讀 19,875評論 0 50
  • 本文內(nèi)容來自菜鳥教程, C++教程榄融,該篇內(nèi)容僅作為筆記使用 繼承 基類 & 派生類 一個類可以派生自多個類参淫,這意味...
    leifuuu閱讀 527評論 0 0
  • 本教程旨在提取最精煉、實用的C++知識點愧杯,供讀者快速學(xué)習(xí)及本人查閱復(fù)習(xí)所用涎才,后期會持續(xù)更新。 基本語法 C++ 語...
    丁俊杰_閱讀 5,894評論 0 8
  • 使用GTEST編寫C++測試用例進(jìn)階教程 [TOC] 更多的斷言 這章覆蓋了一些使用頻率較少但是仍然很重要的斷言 ...
    愿以光散黑閱讀 14,749評論 0 3