C++異常類型以及多級catch

來源:https://www.jianshu.com/p/3858e8c3c822
首先來回顧一下上節講到的 try-catch 的用法:

try{

// 可能拋出異常的語句

}catch(exceptionType variable){

// 處理異常的語句

}

我們還遺留下一個問題,就是 catch 關鍵字後邊的exceptionType variable,這節就來詳細分析一下。

exceptionType是異常類型,它指明瞭當前的 catch 可以處理什麼類型的異常;variable是一個變量,用來接收異常信息。當程序拋出異常時,會創建一份數據,這份數據包含了錯誤信息,程序員可以根據這些信息來判斷到底出了什麼問題,接下來怎麼處理。

異常既然是一份數據,那麼就應該有數據類型。C++ 規定,異常類型可以是 int、char、float、bool 等基本類型,也可以是指針、數組、字符串、結構體、類等聚合類型。C++ 語言本身以及標準庫中的函數拋出的異常,都是 exception 類或其子類的異常。也就是說,拋出異常時,會創建一個 exception 類或其子類的對象。

exceptionType variable和函數的形參非常類似,當異常發生後,會將異常數據傳遞給 variable 這個變量,這和函數傳參的過程類似。當然,只有跟 exceptionType 類型匹配的異常數據纔會被傳遞給 variable,否則 catch 不會接收這份異常數據,也不會執行 catch 塊中的語句。換句話說,catch 不會處理當前的異常。

我們可以將 catch 看做一個沒有返回值的函數,當異常發生後 catch 會被調用,並且會接收實參(異常數據)。

·但是 catch 和真正的函數調用又有區別:

·真正的函數調用,形參和實參的類型必須要匹配,或者可以自動轉換,否則在編譯階段就報錯了。

而對於 catch,異常是在運行階段產生的,它可以是任何類型,沒法提前預測,所以不能在編譯階段判斷類型是否正確,只能等到程序運行後,真的拋出異常了,再將異常類型和 catch 能處理的類型進行匹配,匹配成功的話就“調用”當前的 catch,否則就忽略當前的 catch。

總起來說,catch 和真正的函數調用相比,多了一個「在運行階段將實參和形參匹配」的過程。

另外需要注意的是,如果不希望 catch 處理異常數據,也可以將 variable 省略掉,也即寫作:

try{

// 可能拋出異常的語句

}catch(exceptionType){

// 處理異常的語句

}

這樣只會將異常類型和 catch 所能處理的類型進行匹配,不會傳遞異常數據了。

多級 catch

前面的例子中,一個 try 對應一個 catch,這只是最簡單的形式。其實,一個 try 後面可以跟多個 catch:

try{

//可能拋出異常的語句

}catch(exception_type_1 e){

//處理異常的語句

}catch(exception_type_2 e){

//處理異常的語句

}

//其他的catch

catch(exception_type_n e){

//處理異常的語句

}

當異常發生時,程序會按照從上到下的順序,將異常類型和 catch 所能接收的類型逐個匹配。一旦找到類型匹配的 catch 就停止檢索,並將異常交給當前的 catch 處理(其他的 catch 不會被執行)。如果最終也沒有找到匹配的 catch,就只能交給系統處理,終止程序的運行。

下面的例子演示了多級 catch 的使用:

#include<iostream>

#include<string>

usingnamespacestd;

class Base{};

class Derived:publicBase{};

intmain(){

try{

throwDerived();//拋出自己的異常類型,實際上是創建一個Derived類型的匿名對象

cout<<"This statement will not be executed."<<endl;

}catch(int){

cout<<"Exception type: int"<<endl;

}catch(char*){

cout<<"Exception type: cahr *"<<endl;

}catch(Base){//匹配成功(向上轉型)

cout<<"Exception type: Base"<<endl;

}catch(Derived){

cout<<"Exception type: Derived"<<endl;

}

return0;

}

運行結果:

Exception type: Base

在 catch 中,我們只給出了異常類型,沒有給出接收異常信息的變量。

本例中,我們定義了一個基類 Base,又從 Base 派生類出了 Derived。拋出異常時,我們創建了一個 Derived 類的匿名對象,也就是說,異常的類型是 Derived。

我們期望的是,異常被catch(Derived)捕獲,但是從輸出結果可以看出,異常提前被catch(Base)捕獲了,這說明 catch 在匹配異常類型時發生了向上轉型(Upcasting)。

catch 在匹配過程中的類型轉換

C/C++ 中存在多種多樣的類型轉換,以普通函數(非模板函數)爲例,發生函數調用時,如果實參和形參的類型不是嚴格匹配,那麼會將實參的類型進行適當的轉換,以適應形參的類型,這些轉換包括:

算數轉換:例如 int 轉換爲 float,char 轉換爲 int,double 轉換爲 int 等。

向上轉型:也就是派生類向基類的轉換,請猛擊《C++向上轉型(將派生類賦值給基類)》瞭解詳情。

const 轉換:也即將非 const 類型轉換爲 const 類型,例如將 char 轉換爲 const char

數組或函數指針轉換:如果函數形參不是引用類型,那麼數組名會轉換爲數組指針,函數名也會轉換爲函數指針。

用戶自定的類型轉換。

catch 在匹配異常類型的過程中,也會進行類型轉換,但是這種轉換受到了更多的限制,僅能進行「向上轉型」、「const 轉換」和「數組或函數指針轉換」,其他的都不能應用於 catch。

向上轉型在上面的例子中已經發生了,下面的例子演示了 const 轉換以及數組和指針的轉換:

#include<iostream>

usingnamespacestd;

intmain(){

intnums[]={1,2,3};

try{

thrownums;

cout<<"This statement will not be executed."<<endl;

}catch(constint*){

cout<<"Exception type: const int *"<<endl;

}

return0;

}

運行結果:

Exception type: const int *

nums 本來的類型是int [3],但是 catch 中沒有嚴格匹配的類型,所以先轉換爲int ,再轉換爲const int

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章