異常是一個(gè)程序執(zhí)行過程中出現(xiàn)的問題。C++ 異常是對(duì)程序運(yùn)行過程中產(chǎn)生的例外情況作出的響應(yīng),比如試圖除以零。
異常提供一種方法將程序控制從一個(gè)程序的一部分轉(zhuǎn)移到另一部分。C++ 異常處理是建立在三個(gè)關(guān)鍵詞: 嘗試,捕獲和拋出之上的。
假設(shè)一個(gè)代碼塊將產(chǎn)生一個(gè)異常,結(jié)合使用 try 和 catch 關(guān)鍵詞的方法捕獲了一個(gè)異常。一個(gè) try / catch 塊放置在可能生成一個(gè)異常的代碼周圍。在一個(gè) try / catch 塊里面的代碼被稱為保護(hù)代碼, try / catch 的語法規(guī)則如下:
try
{
// protected code
}catch( ExceptionName e1 )
{
// catch block
}catch( ExceptionName e2 )
{
// catch block
}catch( ExceptionName eN )
{
// catch block
}
你可以列出多個(gè)捕捉語句捕獲不同類型的異常, 以防你的 try 代碼塊在不同的情況下產(chǎn)生了不止一個(gè)異常。
異??梢栽诖a塊的任何地方使用拋出語句拋出。把語句的操作數(shù)確定類型的異常,可以是任何表達(dá)式,表達(dá)式的結(jié)果的類型決定了類型的異常拋出。
下面是一個(gè)例子, 在除以零條件發(fā)生時(shí),拋出異常:
double division(int a, int b)
{
if( b == 0 )
{
throw "Division by zero condition!";
}
return (a/b);
}
try 塊后的 catch 塊可以捕獲任何異常。您可以指定你需要捕獲何種類型的異常,這是由出現(xiàn)在關(guān)鍵字 catch 后邊的括號(hào)中的異常聲明確定的。
try
{
// protected code
}catch( ExceptionName e )
{
// code to handle ExceptionName exception
}
上面的代碼將捕獲到一個(gè) ExceptionName 類型的異常。如果您想要指定一個(gè) catch 塊可以應(yīng)該處理任何在 try 代碼中產(chǎn)生的異常,你必須將一個(gè)省略號(hào)…放在 catch 后的括號(hào)中,異常聲明如下:
try
{
// protected code
}catch(...)
{
// code to handle any exception
}
下面是一個(gè)例子,這個(gè)例子拋出會(huì)除零異常, 我們在 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;
}
因?yàn)樯侠刑岢隽艘粋€(gè) const char *
類型的異常, 所以捕捉這個(gè)異常時(shí),我們必須在 catch 塊中使用const char *
。如果我們編譯和運(yùn)行上面的代碼, 這將產(chǎn)生以下結(jié)果:
Division by zero condition!
C++ 在 <exception>
中提供了一系列標(biāo)準(zhǔn)的異常,我們可以用在我們的程序中。這些異常使用父-子分層結(jié)構(gòu)展示如下:
http://wiki.jikexueyuan.com/project/cplusplus/images/cpp_exceptions.jpg" alt="" />
這是對(duì)上面提到的層次結(jié)構(gòu)中每個(gè)異常的描述:
異常 | 描述 |
---|---|
std::exception | 異常和所有標(biāo)準(zhǔn) C++ 異常的父類 |
std::bad_alloc | 該異常可能會(huì)在使用 new 關(guān)鍵字時(shí)拋出。 |
std::bad_cast | 該異??梢杂?dynamic_cast 拋出。 |
std::bad_exception | 這是一個(gè)在 C++ 程序中處理意想不到的異常的有效手段。 |
std::bad_typeid | 該異常可以由 typeid 拋出。 |
std::logic_error | 理論上可以通過閱讀代碼發(fā)現(xiàn)的異常。 |
std::domain_error | 這是一個(gè)在數(shù)學(xué)無效域被使用時(shí)拋出的異常。 |
std::invalid_argument | 參數(shù)非法時(shí)會(huì)拋出的異常。 |
std::length_error | 太大的 std::string 被創(chuàng)造時(shí),拋出異常。 |
std::out_of_range | 可以拋出該異常的方法例如 std::vector 和 std::bitset ::operator[] ()。 |
std::runtime_error | 理論上不能通過讀代碼檢測到的異常。 |
std::overflow_errorr | 如果出現(xiàn)數(shù)字溢出,則拋出該異常 |
std::range_error | 當(dāng)你試圖存儲(chǔ)一個(gè)超過范圍的值的時(shí)候,會(huì)拋出該異常。 |
std::underflow_error | 如果出現(xiàn)數(shù)學(xué)下溢時(shí),拋出該異常。 |
你可以采用繼承及重寫異常類來。下面是示例, 顯示如何使用 std::exception
類以標(biāo)準(zhǔn)的方式實(shí)現(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)
{
//Other errors
}
}
這將產(chǎn)生如下的結(jié)果:
MyException caught
C++
這里,what()
是一個(gè)異常類提供的公共方法,所有子異常類都覆蓋了該方法。這將返回一個(gè)異常的原因。