如果您喜歡玩一款游戲,您必須先要很好理解這款游戲的規則。同樣主人公阿愚喜歡上C++中異常處理后,當然也首先關注它的游戲規則,這就是C++中異常處理的語法。
關鍵字
1、 try
2、 catch
3、 throw
其中關鍵字try表示定義一個受到監控、受到保護的程序代碼塊;關鍵字catch與try遙相呼應,定義當try block(受監控的程序塊)出現異常時,錯誤處理的程序模塊,并且每個catch block都帶一個參數(類似于函數定義時的數那樣),這個參數的數據類型用于異常對象的數據類型進行匹配;而throw則是檢測到一個異常錯誤發生后向外拋出一個異常事件,通知對應的catch程序塊執行對應的錯誤處理。
語法
1、還是給一個例子吧!如下:
int main()
{
cout << "In main." << endl;
//定義一個try block,它是用一對花括號{}所括起來的塊作用域的代碼塊
try
{
cout << "在 try block 中, 準備拋出一個異常." << endl;
//這里拋出一個異常(其中異常對象的數據類型是int,值為1)
//由于在try block中的代碼是受到監控保護的,所以拋出異常后,程序的
//控制流便轉到隨后的catch block中
throw 1;
cout << "在 try block 中, 由于前面拋出了一個異常,因此這里的代碼是不會得以執行到的" << endl;
}
//這里必須相對應地,至少定義一個catch block,同樣它也是用花括號括起來的
catch( int& value )
{
cout << "在 catch block 中, 處理異常錯誤。異常對象value的值為:"<< value << endl;
}
cout << "Back in main. Execution resumes here." << endl;
return 0;
}
2、語法很簡單吧!的確如此。另外一個try block可以有多個對應的catch block,可為什么要多個catch block呢?這是因為每個catch block匹配一種類型的異常錯誤對象的處理,多個catch block呢就可以針對不同的異常錯誤類型分別處理。畢竟異常錯誤也是分級別的呀!有致命的、有一般的、有警告的,甚至還有的只是事件通知。例子如下:
int main()
{
try
{
cout << "在 try block 中, 準備拋出一個int數據類型的異常." << endl;
throw 1;
cout << "在 try block 中, 準備拋出一個double數據類型的異常." << endl;
throw 0.5;
}
catch( int& value )
{
cout << "在 catch block 中, int數據類型處理異常錯誤。”<< endl;
}
catch( double& d_value )
{
cout << "在 catch block 中, double數據類型處理異常錯誤。”<< endl;
}
return 0;
}
3、一個函數中可以有多個trycatch結構塊,例子如下:
int main()
{
try
{
cout << "在 try block 中, 準備拋出一個int數據類型的異常." << endl;
throw 1;
}
catch( int& value )
{
cout << "在 catch block 中, int數據類型處理異常錯誤。”<< endl;
}
//這里是二個trycatch結構塊,當然也可以有第三、第四個,甚至更多
try
{
cout << "在 try block 中, 準備拋出一個double數據類型的異常." << endl;
throw 0.5;
}
catch( double& d_value )
{
cout << "在 catch block 中, double數據類型處理異常錯誤。”<< endl;
}
return 0;
}
4、上面提到一個try block可以有多個對應的catch block,這樣便于不同的異常錯誤分類處理,其實這只是異常錯誤分類處理的方法之一(暫且把它叫做橫向展開的吧!)。另外還有一種就是縱向的,也即是分層的、trycatch塊是可以嵌套的,當在低層的trycatch結構塊中不能匹配到相同類型的catch block時,它就會到上層的trycatch塊中去尋找匹配到正確的catch block異常處理模塊。例程如下:
int main()
{
try
{
//這里是嵌套的trycatch結構塊
try
{
cout << "在 try block 中, 準備拋出一個int數據類型的異常." << endl;
throw 1;
}
catch( int& value )
{
cout << "在 catch block 中, int數據類型處理異常錯誤。”<< endl;
}
cout << "在 try block 中, 準備拋出一個double數據類型的異常." << endl;
throw 0.5;
}
catch( double& d_value )
{
cout << "在 catch block 中, double數據類型處理異常錯誤。”<< endl;
}
return 0;
}
5、講到是trycatch塊是可以嵌套分層的,并且通過異常對象的數據類型來進行匹配,以找到正確的catch block異常錯誤處理代碼。這里就不得不詳細敘述一下通過異常對象的數據類型來進行匹配找到正確的catch block的過程。
(1) 首先在拋出異常的trycatch塊中查找catch block,按順序先是與第一個catch block塊匹配,如果拋出的異常對象的數據類型與catch block中傳入的異常對象的臨時變量(就是catch語句后面參數)的數據類型完全相同,或是它的子類型對象,則匹配成功,進入到catch block中執行;否則到二步;
(2) 如果有二個或更多的catch block,則繼續查找匹配第二個、第三個,乃至最后一個catch block,如匹配成功,則進入到對應的catch block中執行;否則到三步;
(3) 返回到上一級的trycatch塊中,按規則繼續查找對應的catch block。如果找到,進入到對應的catch block中執行;否則到四步;
(4) 再到上上級的trycatch塊中,如此不斷遞歸,直到匹配到頂級的trycatch塊中的最后一個catch block,如果找到,進入到對應的catch block中執行;否則程序將會執行terminate()退出。
另外分層嵌套的trycatch塊是可以跨越函數作用域的,例程如下:
void Func() throw()
{
//這里實際上也是嵌套在里層的trycatch結構塊
try
{
cout << "在 try block 中, 準備拋出一個int數據類型的異常." << endl;
//由于這個trycatch塊中不能找到匹配的catch block,所以
//它會繼續查找到調用這個函數的上層函數的trycatch塊。
throw 1;
}
catch( float& value )
{
cout << "在 catch block 中, int數據類型處理異常錯誤。”<< endl;
}
}
int main()
{
try
{
Func();
cout << "在 try block 中, 準備拋出一個double數據類型的異常." << endl;
throw 0.5;
}
catch( double& d_value )
{
cout << "在 catch block 中, double數據類型處理異常錯誤。”<< endl;
}
catch( int& value )
{
//這個例子中,Func()函數中拋出的異常會在此被處理
cout << "在 catch block 中, int數據類型處理異常錯誤。”<< endl;
}
return 0;
}
6、剛才提到,嵌套的trycatch塊是可以跨越函數作用域的,其實這里面還有另外一層涵義,就是拋出異常對象的函數中并不一定必須存在trycatch塊,它可以是調用這個函數的上層函數中存在trycatch塊,這樣這個函數的代碼也同樣是受保護、受監控的代碼;當然即便是上層調用函數不存在trycatch塊,也只是不能找到處理這類異常對象錯誤處理的catch block而已,例程如下:
void Func() throw()
{
//這里實際上也是嵌套在里層的trycatch結構塊
//由于這個函數中是沒有trycatch塊的,所以它會查找到調用這個函數的上
//層函數的trycatch塊中。
throw 1;
}
int main()
{
try
{
//調用函數,注意這個函數里面拋出一個異常對象
Func();
cout << "在 try block 中, 準備拋出一個double數據類型的異常." << endl;
throw 0.5;
}
catch( double& d_value )
{
cout << "在 catch block 中, double數據類型處理異常錯誤。”<< endl;
}
catch( int& value )
{
//這個例子中,Func()函數中拋出的異常會在此被處理
cout << "在 catch block 中, int數據類型處理異常錯誤。”<< endl;
}
//如果這里調用這個函數,那么由于main()已經是調用棧的頂層函數,因此不能找
//到對應的catch block,所以程序會執行terminate()退出。
Func();
// [特別提示]:在C++標準中規定,可以在程序任何地方throw一個異常對象,
// 并不要求一定只能是在受到try block監控保護的作用域中才能拋出異常,但
// 如果在程序中出現了拋出的找不到對應catch block的異常對象時,C++標
// 準中規定要求系統必須執行terminate()來終止程序。
// 因此這個例程是可以編譯通過的,但運行時卻會異常終止。這往往給軟件
// 系統帶來了不安全性。與此形成對比的是java中提供的異常處理模型卻是不
// 永許出現這樣的找不到對應catch block的異常對象,它在編譯時就給出錯誤
// 提示,所以java中提供的異常處理模型往往比C++要更完善,后面的章節
// 會進一步對這兩種異常處理模型進行一個詳細的分析比較。
return 0;
}
朋友們!C++中的異常處理模型的語法很簡單吧!就是那么(one、two、three、…哈哈!數數呢!)簡單的幾條規則。怪不得主人公阿愚這么快就喜歡上她了,而且還居然像一個思想家一樣總結出一條感想:好的東西往往都是簡單的,簡單就是美嗎!哈哈!還挺臭美的。
下一集主人公阿愚愿和大家一起討論一下C++中的異常處理中的一種特殊的catch用法,那就是關于catch(…)大探秘。
from: http://51cmm.csai.cn/ExpertEyes/No137.htm