為了能夠編寫適當的catch子句,了解一個函數是否拋出異常或會拋出哪些異常對函數的用戶來說是很有幫助的。
而我們可以通過 異常說明 進行對一個函數的異常進行說明, 如果函數拋出異常,被拋出的異常將是包含在該說明中的一種或是從列出的異常中派生的類型。
異常說明有如下的幾種形式:
1. 指定異常
T funNname( parameterlist ) throw( T1, T2,····,Tn);
其中 T 是類型, parameterlist 是參數列表, 而類型 T1, T2,····,Tn 是函數會拋出的異常。
2. 不拋出異常
T funNname( parameterlist ) throw( );
拋出異常類型列表為空,表示的是該函數不拋出任何類型異常。
3. 拋出任意類型的異常
T funNname( parameterlist );
這表示該函數可以拋出任意類型的異常。
下面通過一段簡單的代碼來說明異常說明的特別之處
[cpp]
#include <iostream>
class demo
{
};
using namespace std;
double divd(int a, int b) throw(int) //異常說明,表示函數divd會拋出類型為int的異常
{
if(b == 0) throw demo(); //拋出類型為demo的異常
return a/b;
}
int main()
{
try
{
divd(1,0);
}
catch(demo) //捕獲異常類型demo
{
cout << " divided by zero " << endl;
}
catch(int) //捕獲異常類型int
{
cout<<"zero"<<endl;
}
return 0;
}
這段代碼的運行結果是輸出: divided by zero
奇怪了,在 divd 函數的聲明中,只說明了拋出類型為 int 的異常,為什麼其函數內拋出的異常類型卻為demo呢?
我們可以暫時理解為:在某函數的異常說明中的列出的類型與該函數內拋出的異常類型不完全匹配時, 但在異常處理代碼中的catch有對其類型的捕獲, 所以程序運行正常。
好,下面我們根據異常說明進行一些修改
[cpp]
double divd(int a, int b) throw( ) //將throw(int) 改為 throw( )
修改之後,編譯運行,看到的輸出結果還是: divided by zero
根據上面對異常說明的三種形式介紹,我們知道在函數聲明後面添加 throw()的意思是說明了此函數不會拋出任何的異常。那為什麼這裡拋出了而且又被捕獲呢?
其實,在編譯的時候,編譯器不能也不會試圖驗證異常說明。因不能在編譯時檢查異常說明,異常說明的應用通常是有限的!
修改後的 divd 函數內繼續編寫有拋出異常的代碼, 編譯後再次運行程序,其輸出結果也表示異常機制執行正常。
其原因就如上述所說的理解那樣:編譯器不會對異常說明進行檢測,異常說明更多的是寫給函數的用戶看。
而在一開始函數異常說明的類型與實際拋出的異常類型不匹配的情況中,同樣由於 “編譯器不會對異常說明進行檢測” 的原因,所以編譯通過,異常機制運行正常。
總結:異常說明還是有用的!但更多是寫給函數用戶看的。讓函數用戶清楚知道拋出的異常類型,從而更好和正確地在運用此函數時,編寫對其的異常檢測。
由於初學者在學語法的時候,更多的只是看書,不進行實踐驗證。就算實踐驗證了,也可能只是照書上代碼敲,看看運行結果是否一樣。這裡給出一個建議:初學者在學習語法的時候,應該多上機實踐驗證書上語法的准確性,就算運行結果與書上一致,也應該多動腦筋,對其進行變形或改動。這樣往往能學到的東西和印象都會更深的!