C++中怎么使用trythrowcatch進(jìn)行異常處理

本篇文章給大家分享的是有關(guān)C++中怎么使用trythrowcatch進(jìn)行異常處理,小編覺(jué)得挺實(shí)用的,因此分享給大家學(xué)習(xí),希望大家閱讀完這篇文章后可以有所收獲,話不多說(shuō),跟著小編一起來(lái)看看吧。

公司主營(yíng)業(yè)務(wù):成都網(wǎng)站設(shè)計(jì)、成都網(wǎng)站建設(shè)、外貿(mào)網(wǎng)站建設(shè)、移動(dòng)網(wǎng)站開(kāi)發(fā)等業(yè)務(wù)。幫助企業(yè)客戶真正實(shí)現(xiàn)互聯(lián)網(wǎng)宣傳,提高企業(yè)的競(jìng)爭(zhēng)能力。創(chuàng)新互聯(lián)是一支青春激揚(yáng)、勤奮敬業(yè)、活力青春激揚(yáng)、勤奮敬業(yè)、活力澎湃、和諧高效的團(tuán)隊(duì)。公司秉承以“開(kāi)放、自由、嚴(yán)謹(jǐn)、自律”為核心的企業(yè)文化,感謝他們對(duì)我們的高要求,感謝他們從不同領(lǐng)域給我們帶來(lái)的挑戰(zhàn),讓我們激情的團(tuán)隊(duì)有機(jī)會(huì)用頭腦與智慧不斷的給客戶帶來(lái)驚喜。創(chuàng)新互聯(lián)推出寬城免費(fèi)做網(wǎng)站回饋大家。

C++異常處理基本語(yǔ)法

C++ 通過(guò) throw 語(yǔ)句和 try…catch 語(yǔ)句實(shí)現(xiàn)對(duì)異常的處理。throw 語(yǔ)句的語(yǔ)法如下:

throw 表達(dá)式;

該語(yǔ)句拋出一個(gè)異常。異常是一個(gè)表達(dá)式,其值的類型可以是基本類型,也可以是類。

try…catch 語(yǔ)句的語(yǔ)法如下:

try { 語(yǔ)句組}catch(異常類型) { 異常處理代碼}...catch(異常類型) { 異常處理代碼}

catch 可以有多個(gè),但至少要有一個(gè)。

不妨把 try 和其后{}中的內(nèi)容稱作“try塊”,把 catch 和其后{}中的內(nèi)容稱作“catch塊”。

try…catch 語(yǔ)句的執(zhí)行過(guò)程是:

執(zhí)行 try 塊中的語(yǔ)句,如果執(zhí)行的過(guò)程中沒(méi)有異常拋出,那么執(zhí)行完后就執(zhí)行最后一個(gè) catch 塊后面的語(yǔ)句,所有 catch 塊中的語(yǔ)句都不會(huì)被執(zhí)行;  如果 try 塊執(zhí)行的過(guò)程中拋出了異常,那么拋出異常后立即跳轉(zhuǎn)到第一個(gè)“異常類型”和拋出的異常類型匹配的 catch 塊中執(zhí)行(稱作異常被該 catch 塊“捕獲”),執(zhí)行完后再跳轉(zhuǎn)到最后一個(gè) catch 塊后面繼續(xù)執(zhí)行。

例如下面的程序:

#include <iostream>using namespace std;int main(){ double m ,n; cin >> m >> n; try {  cout << "before piding." << endl;  if( n == 0)   throw -1; //拋出int類型異常  else   cout << m / n << endl;  cout << "after piding." << endl; } catch(double d) {  cout << "catch(double) " << d << endl; } catch(int e) {  cout << "catch(int) " << e << endl; } cout << "finished" << endl; return 0;}

程序的運(yùn)行結(jié)果如下:

9 6↙before piding.1.5after piding.finished

說(shuō)明當(dāng) n 不為 0 時(shí),try 塊中不會(huì)拋出異常。因此程序在 try 塊正常執(zhí)行完后,越過(guò)所有的 catch 塊繼續(xù)執(zhí)行,catch 塊一個(gè)也不會(huì)執(zhí)行。

程序的運(yùn)行結(jié)果也可能如下:

9 0↙before piding.catch\(int) -1finished

當(dāng) n 為 0 時(shí),try 塊中會(huì)拋出一個(gè)整型異常。拋出異常后,try 塊立即停止執(zhí)行。該整型異常會(huì)被類型匹配的第一個(gè) catch 塊捕獲,即進(jìn)入 catch(int e) 塊執(zhí)行,該 catch 塊執(zhí)行完畢后,程序繼續(xù)往后執(zhí)行,直到正常結(jié)束。

如果拋出的異常沒(méi)有被 catch 塊捕獲,例如,將catch(int e),改為catch(char e),當(dāng)輸入的 n 為 0 時(shí),拋出的整型異常就沒(méi)有 catch 塊能捕獲,這個(gè)異常也就得不到處理,那么程序就會(huì)立即中止,try…catch 后面的內(nèi)容都不會(huì)被執(zhí)行。

能夠捕獲任何異常的 catch 語(yǔ)句

如果希望不論拋出哪種類型的異常都能捕獲,可以編寫如下 catch 塊:

catch(...) { ...}

這樣的 catch 塊能夠捕獲任何還沒(méi)有被捕獲的異常。例如下面的程序:

#include <iostream>using namespace std;int main(){  double m, n;  cin >> m >> n;  try {    cout << "before piding." << endl;    if (n == 0)      throw - 1; //拋出整型異常    else if (m == 0)      throw - 1.0; //拋出 double 型異常    else      cout << m / n << endl;    cout << "after piding." << endl;  }  catch (double d) {    cout << "catch (double)" << d << endl;  }  catch (...) {    cout << "catch (...)" << endl;  }  cout << "finished" << endl;  return 0;}

程序的運(yùn)行結(jié)果如下:

9 0↙before piding.catch (...)finished

當(dāng) n 為 0 時(shí),拋出的整型異常被catchy(...)捕獲。

程序的運(yùn)行結(jié)果也可能如下:

0 6↙before piding.catch (double) -1finished

當(dāng) m 為 0 時(shí),拋出一個(gè) double 類型的異常。雖然catch (double)和catch(...)都能匹配該異常,但是catch(double)是第一個(gè)能匹配的 catch 塊,因此會(huì)執(zhí)行它,而不會(huì)執(zhí)行catch(...)塊。

由于catch(...)能匹配任何類型的異常,它后面的 catch 塊實(shí)際上就不起作用,因此不要將它寫在其他 catch 塊前面。

異常的再拋出

如果一個(gè)函數(shù)在執(zhí)行過(guò)程中拋出的異常在本函數(shù)內(nèi)就被 catch 塊捕獲并處理,那么該異常就不會(huì)拋給這個(gè)函數(shù)的調(diào)用者(也稱為“上一層的函數(shù)”);如果異常在本函數(shù)中沒(méi)有被處理,則它就會(huì)被拋給上一層的函數(shù)。

例如下面的程序:

#include <iostream>#include <string>using namespace std;class CException{public:  string msg;  CException(string s) : msg(s) {}};double Devide(double x, double y){  if (y == 0)    throw CException("devided by zero");  cout << "in Devide" << endl;  return x / y;}int CountTax(int salary){  try {    if (salary < 0)      throw - 1;    cout << "counting tax" << endl;  }  catch (int) {    cout << "salary < 0" << endl;  }  cout << "tax counted" << endl;  return salary * 0.15;}int main(){  double f = 1.2;  try {    CountTax(-1);    f = Devide(3, 0);    cout << "end of try block" << endl;  }  catch (CException e) {    cout << e.msg << endl;  }  cout << "f = " << f << endl;  cout << "finished" << endl;  return 0;}

程序的輸出結(jié)果如下:

salary < 0tax counteddevided by zerof=1.2finished

CountTa 函數(shù)拋出異常后自行處理,這個(gè)異常就不會(huì)繼續(xù)被拋給調(diào)用者,即 main 函數(shù)。因此在 main 函數(shù)的 try 塊中,CountTax 之后的語(yǔ)句還能正常執(zhí)行,即會(huì)執(zhí)行f = Devide(3, 0);。

第 35 行,Devide 函數(shù)拋出了異常卻不處理,該異常就會(huì)被拋給 Devide 函數(shù)的調(diào)用者,即 main 函數(shù)。拋出此異常后,Devide 函數(shù)立即結(jié)束,第 14 行不會(huì)被執(zhí)行,函數(shù)也不會(huì)返回一個(gè)值,這從第 35 行 f 的值不會(huì)被修改可以看出。

Devide 函數(shù)中拋出的異常被 main 函數(shù)中類型匹配的 catch 塊捕獲。第 38 行中的 e 對(duì)象是用復(fù)制構(gòu)造函數(shù)初始化的。

如果拋出的異常是派生類的對(duì)象,而 catch 塊的異常類型是基類,那么這兩者也能夠匹配,因?yàn)榕缮悓?duì)象也是基類對(duì)象。

雖然函數(shù)也可以通過(guò)返回值或者傳引用的參數(shù)通知調(diào)用者發(fā)生了異常,但采用這種方式的話,每次調(diào)用函數(shù)時(shí)都要判斷是否發(fā)生了異常,這在函數(shù)被多處調(diào)用時(shí)比較麻煩。有了異常處理機(jī)制,可以將多處函數(shù)調(diào)用都寫在一個(gè) try 塊中,任何一處調(diào)用發(fā)生異常都會(huì)被匹配的 catch 塊捕獲并處理,也就不需要每次調(diào)用后都判斷是否發(fā)生了異常。

有時(shí),雖然在函數(shù)中對(duì)異常進(jìn)行了處理,但是還是希望能夠通知調(diào)用者,以便讓調(diào)用者知道發(fā)生了異常,從而可以作進(jìn)一步的處理。在 catch 塊中拋出異常可以滿足這種需要。例如:

#include <iostream>#include <string>using namespace std;int CountTax(int salary){  try {    if( salary < 0 )      throw string("zero salary");    cout << "counting tax" << endl;  }  catch (string s ) {    cout << "CountTax error : " << s << endl;    throw; //繼續(xù)拋出捕獲的異常  }  cout << "tax counted" << endl;  return salary * 0.15;}int main(){  double f = 1.2;  try {    CountTax(-1);    cout << "end of try block" << endl;  }  catch(string s) {    cout << s << endl;  }  cout << "finished" << endl;  return 0;}

程序的輸出結(jié)果如下:

CountTax error:zero salaryzero salaryfinished

第 14 行的throw;沒(méi)有指明拋出什么樣的異常,因此拋出的就是 catch 塊捕獲到的異常,即 string("zero salary")。這個(gè)異常會(huì)被 main 函數(shù)中的 catch 塊捕獲。

函數(shù)的異常聲明列表

為了增強(qiáng)程序的可讀性和可維護(hù)性,使程序員在使用一個(gè)函數(shù)時(shí)就能看出這個(gè)函數(shù)可能會(huì)拋出哪些異常,C++ 允許在函數(shù)聲明和定義時(shí),加上它所能拋出的異常的列表,具體寫法如下:

void func() throw (int, double, A, B, C);

void func() throw (int, double, A, B, C){...}

上面的寫法表明 func 可能拋出 int 型、double 型以及 A、B、C 三種類型的異常。異常聲明列表可以在函數(shù)聲明時(shí)寫,也可以在函數(shù)定義時(shí)寫。如果兩處都寫,則兩處應(yīng)一致。

如果異常聲明列表如下編寫:

void func() throw ();

則說(shuō)明 func 函數(shù)不會(huì)拋出任何異常。

一個(gè)函數(shù)如果不交待能拋出哪些類型的異常,就可以拋出任何類型的異常。

函數(shù)如果拋出了其異常聲明列表中沒(méi)有的異常,在編譯時(shí)不會(huì)引發(fā)錯(cuò)誤,但在運(yùn)行時(shí), Dev C++ 編譯出來(lái)的程序會(huì)出錯(cuò);用 Visual Studio 2010 編譯出來(lái)的程序則不會(huì)出錯(cuò),異常聲明列表不起實(shí)際作用。

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

C++ 標(biāo)準(zhǔn)庫(kù)中有一些類代表異常,這些類都是從 exception 類派生而來(lái)的。常用的幾個(gè)異常類如圖 1 所示。

圖1:常用的異常類

bad_typeid、bad_cast、bad_alloc、ios_base::failure、out_of_range 都是 exception 類的派生類。C++ 程序在碰到某些異常時(shí),即使程序中沒(méi)有寫 throw 語(yǔ)句,也會(huì)自動(dòng)拋出上述異常類的對(duì)象。這些異常類還都有名為 what 的成員函數(shù),返回字符串形式的異常描述信息。使用這些異常類需要包含頭文件 stdexcept。

下面分別介紹以上幾個(gè)異常類。本節(jié)程序的輸出以 Visual Studio 2010為準(zhǔn),Dev C++ 編譯的程序輸出有所不同。

1) bad_typeid

使用 typeid 運(yùn)算符時(shí),如果其操作數(shù)是一個(gè)多態(tài)類的指針,而該指針的值為 NULL,則會(huì)拋出此異常。

2) bad_cast

在用 dynamic_cast 進(jìn)行從多態(tài)基類對(duì)象(或引用)到派生類的引用的強(qiáng)制類型轉(zhuǎn)換時(shí),如果轉(zhuǎn)換是不安全的,則會(huì)拋出此異常。程序示例如下:

#include <iostream>#include <stdexcept>using namespace std;class Base{  virtual void func() {}};class Derived : public Base{public:  void Print() {}};void PrintObj(Base & b){  try {    Derived & rd = dynamic_cast <Derived &>(b);    //此轉(zhuǎn)換若不安全,會(huì)拋出 bad_cast 異常    rd.Print();  }  catch (bad_cast & e) {    cerr << e.what() << endl;  }}int main(){  Base b;  PrintObj(b);  return 0;}

程序的輸出結(jié)果如下:

Bad dynamic_cast!

在 PrintObj 函數(shù)中,通過(guò) dynamic_cast 檢測(cè) b 是否引用的是一個(gè) Derived 對(duì)象,如果是,就調(diào)用其 Print 成員函數(shù);如果不是,就拋出異常,不會(huì)調(diào)用 Derived::Print。

3) bad_alloc

在用 new 運(yùn)算符進(jìn)行動(dòng)態(tài)內(nèi)存分配時(shí),如果沒(méi)有足夠的內(nèi)存,則會(huì)引發(fā)此異常。程序示例如下:

#include <iostream>#include <stdexcept>using namespace std;int main(){  try {    char * p = new char[0x7fffffff]; //無(wú)法分配這么多空間,會(huì)拋出異常  }  catch (bad_alloc & e) {    cerr << e.what() << endl;  }  return 0;}

程序的輸出結(jié)果如下:

bad allocationios_base::failure

在默認(rèn)狀態(tài)下,輸入輸出流對(duì)象不會(huì)拋出此異常。如果用流對(duì)象的 exceptions 成員函數(shù)設(shè)置了一些標(biāo)志位,則在出現(xiàn)打開(kāi)文件出錯(cuò)、讀到輸入流的文件尾等情況時(shí)會(huì)拋出此異常。此處不再贅述。

4) out_of_range

用 vector 或 string 的 at 成員函數(shù)根據(jù)下標(biāo)訪問(wèn)元素時(shí),如果下標(biāo)越界,則會(huì)拋出此異常。例如:

#include <iostream>#include <stdexcept>#include <vector>#include <string>using namespace std;int main(){  vector<int> v(10);  try {    v.at(100) = 100; //拋出 out_of_range 異常  }  catch (out_of_range & e) {    cerr << e.what() << endl;  }  string s = "hello";  try {    char c = s.at(100); //拋出 out_of_range 異常  }  catch (out_of_range & e) {    cerr << e.what() << endl;  }  return 0;}

程序的輸出結(jié)果如下:

invalid vector <T> subscriptinvalid string position

如果將v.at(100)換成v[100],將s.at(100)換成s[100],程序就不會(huì)引發(fā)異常(但可能導(dǎo)致程序崩潰)。因?yàn)?at 成員函數(shù)會(huì)檢測(cè)下標(biāo)越界并拋出異常,而 operator[] 則不會(huì)。operator [] 相比 at 的好處就是不用判斷下標(biāo)是否越界,因此執(zhí)行速度更快。

以上就是C++中怎么使用trythrowcatch進(jìn)行異常處理,小編相信有部分知識(shí)點(diǎn)可能是我們?nèi)粘9ぷ鲿?huì)見(jiàn)到或用到的。希望你能通過(guò)這篇文章學(xué)到更多知識(shí)。更多詳情敬請(qǐng)關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道。

網(wǎng)頁(yè)名稱:C++中怎么使用trythrowcatch進(jìn)行異常處理
文章分享:http://bm7419.com/article10/igiigo.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供虛擬主機(jī)、電子商務(wù)、面包屑導(dǎo)航、外貿(mào)網(wǎng)站建設(shè)、網(wǎng)站營(yíng)銷品牌網(wǎng)站設(shè)計(jì)

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來(lái)源: 創(chuàng)新互聯(lián)

外貿(mào)網(wǎng)站建設(shè)