**在這里總結一下,C++中的異常機制,以及如何使用異常的知識點**
C++中處理異常的過程是這樣的:在執行程序發生異常,可以不在本函數中處理,而是拋出一個錯誤信息,把它傳遞給上一級的函數來解決,上一級解決不了,再傳給其上一級,由其上一級處理。如此逐級上傳,直到最高一級還無法處理的話,運行系統會自動調用系統函數terminate,由它調用abort終止程序。這樣的異常處理方法使得異常引發和處理機制分離,而不在同一個函數中處理。這使得底層函數只需要解決實際的任務,而不必過多考慮對異常的處理,而把異常處理的任務交給上一層函數去處理。
總結C++異常機制的用法概念
首先異常機制中最重要的三個關鍵字就是:throw?? try?? catch。
Throw拋出異常,try 包含異常模塊,catch 捕捉拋出的異常,三者各有各的分工,集成在一起就構成了異常的基本機制。
**我們為什么要檢測異常,拋出異常,?**
程序做錯誤檢查是必要的,通常我們可以通過返回值告訴客戶有了錯誤,不過異常提供了更加方便的手段和豐富的信息。舉個例子,一個游戲軟件,需要判斷你在打游戲中選擇的關口(類似于地下城勇士中勇士級,王者級等


),其中每一個關口都對應這一個ID(這是必須的),當你等級不夠時,不能選擇高等級的,此時就要拋出一個異常,提示你等級不夠,不可以進入,例子可能有些不恰當,但足以說明使用異常處理的重要性。廢話不說了,下面詳細介紹下如何使用異常處理。
如果在try語句塊的程序段中(包括在其中調用的函數)發現了異常,且拋棄了該異常,則這個異常就可以被try語句塊后的某個catch語句所捕獲并處理,捕獲和處理的條件是被拋棄的異常的類型與catch語句的異常類型相匹配。由于C++使用數據類型來區分不同的異常,因此在判斷異常時,throw語句中的表達式的值就沒有實際意義,而表達式的類型就特別重要
以異常語句如下:
~~~
try
{
可能會出異常的函數或者語句,判斷是否出現異常,拋出異常
}
Catch(異常類型 [參數名字] )
{
捕捉異常
}
~~~
其中catch語句可以有多個,以捕捉不同的異常。
(1)異常類型我們可以使用自己定義的,我們寫一個程序,除法程序,除數為零,自定義拋出異常類型。
~~~
#include<iostream>
#include<stdexcept>
using namespace std;
class divide_zero //自定義異常類型
{};
int divide(int c, int d) //定義函數,異常類型說明 此處不寫,則說明是此函數有可能拋出各種異常
{
if(d==0)
throw divide_zero();//拋出異常類型為 除零異常類型
cout<<"Correct the result is"<<c/d<<endl;
return 0;
}
int main()
{
int a,b; ?
~~~
~~~
//使用自定義異常類型
cout<<"Please enter the two different integer "<<endl;
cin>>a>>b;
try
{
divide(a,b); //可能發生異常的函數
}
catch(divide_zero) //捕捉到除數為零的異常
{
cout<<"Division by zero"<<endl;
}
return 0;
}
~~~
運行結果是:
(2)異常類型可以是我們定義的類,我們也可以定義異常類型是基本數據類型,為此,我們修改上述代碼
? ? ?
~~~
#include<iostream>
#include<stdexcept>
using namespace std;
int divide(int x,int y)
{
if(y==0)
throw y;
cout<<"Correct the result is"<<x/y<<endl;
return 0;
}
int main()
{
//自定義類型之使用基本數據類型
try
{
divide(1,0);
}
catch(<span style="color:#ff0000;">int</span>) //<span style="color:#ff0000;">因為除數是整形所以拋出異常時類型是整形才能捕捉(0也是整形)</span>
{
cerr<<"error of dividing zero./n";
exit(1); //異常退出程序
}
}
~~~
運行結果是:
此時我們也可以用C++的標準異常,為此我們修改上面代碼,我們先介紹下C++的標準異常類,使用C++提供給我們的標準異常時,我們需要包含頭文件#include<stdexcept>
以下是我查找的C++標準異常類型,引用一個大神
的文章
~~~
namespace std
{
?? //exception派生
?? class logic_error; //邏輯錯誤,在程序運行前可以檢測出來
?? //logic_error派生
?? class domain_error; //違反了前置條件
?? class invalid_argument; //指出函數的一個無效參數
?? class length_error; //指出有一個超過類型size_t的最大可表現值長度的對象的企圖
?? class out_of_range; //參數越界
?? class bad_cast; //在運行時類型識別中有一個無效的dynamic_cast表達式
?? class bad_typeid; //報告在表達試typeid(*p)中有一個空指針p
?? //exception派生
?? class runtime_error; //運行時錯誤,僅在程序運行中檢測到
?? //runtime_error派生
?? class range_error; //違反后置條件
?? class overflow_error; //報告一個算術溢出
?? class bad_alloc; //存儲分配錯誤
}
~~~
其中的一個重要函數為what(),它返回一個表示異常的字符串指針。
標準庫異常類定義在以下四個頭文件中
1、exception頭文件:定義了最常見的標準異常類,其類名為exception。只通知異常的產生,但不會提供更多的信息
2、stdexcept頭文件定義了以下幾種常見異常類
函數????????????????????????????????????????????????????功能或作用
exception???????????????????????????????????????????????最常見的問題
runtime_error????????????????????????????????????????? 運行時錯誤:僅在運行時才能檢測到的問題
range_error???????????????????????????????????????????? 運行時錯誤:生成的結果超出了有意義的值域范圍
overflow_error??????????????????????????????????????? 運行時錯誤:計算上溢
underflow_error?????????????????????????????????????運行時錯誤:計算下溢
logic_error???????????????????????????????????????????????邏輯錯誤:可在運行前檢測到的問題
domain_error????????????????????????????????????????? 邏輯錯誤:參數的結果值不存在
invalid_argument??????????????????????????????????? 邏輯錯誤:不合適的參數
length_error???????????????????????????????????????????? 邏輯錯誤:試圖生成一個超出該類型最大長度的對象
out_of_range??????????????????????????????????????????? 邏輯錯誤:使用一個超出有效范圍的值
了解完后,我們開始編寫程序,在此我們只是簡單地使用下標準異常類。
~~~
#include<iostream>
#include<stdexcept>
using namespace std;
int main()
{
//拋出一個小小的異常 使用C++標準異常類
int a,b;
cout<<"Please enter the two different integer "<<endl;
while(cin>>a>>b)
{
try
{
if(b==0)
throw runtime_error("兩者不可以相等");
}
catch(runtime_error err)
{
cout<<err.what()<<endl;
}
cout<<"請繼續輸入"<<endl;
}
return 0;
}
~~~
運行結果是:
**異常的接口聲明**
為了加強程序的可讀性,使函數的用戶能夠方便地知道所使用的函數會拋出哪些異常,可以在函數的聲明中列出這個函數可能拋出的所有異常類型,例如:
`void fun() throw( A,B,C,D);`
這表明函數fun()可能并且只可能拋出類型(A,B,C,D)及其子類型的異常。如果在函數的聲明中沒有包括異常的接口聲明,則此函數可以拋出任何類型的異常,例如:
`void fun();`
一個不會拋出任何類型異常的函數可以進行如下形式的聲明:
`void fun() thow();`
此時一定要注意:編譯器不會對異常說明進行檢測,異常說明更多的是寫給函數的用戶看。
而在一開始函數異常說明的類型與實際拋出的異常類型不匹配的情況中,同樣由于“編譯器不會對異常說明進行檢測”的原因,所以編譯通過,異常機制運行正常。比如說,你的聲明的類型是整形,結果還是讓除數為零的異常接收到了,有人感覺很奇怪,其原因就在于此。
