C++ 與 物件導向 程式設計概念簡介 魏天君 d908301@oz.nthu.edu.tw 2019/5/3
使用異常處理的優點 錯誤處理程式碼可以與引起錯誤的程式碼分開 在函式中發生錯誤時,可以回傳某種錯誤碼通知呼叫者,使呼叫者決定其最好的處理方式 2019/5/3
異常處理的語法 try { // Code that may throw exceptions } catch(exceptionType e1) // Code to handle the exception catch(exceptionTyp e2) 2019/5/3
異常處理的語法 try { if(test > 5) throw "test is greater than 5"; // This code will execute if the exception is not thrown } catch(const char *message) cout << message << endl; 2019/5/3
丟出及攔截異常 範例 7.1 丟出異常會立即從 try 區塊移轉出控制權 若無異常丟出,則沒有一個 catch 區塊會執行 catch 區塊的參數型別必需符合丟出的異常,此 catch 區塊才會執行 2019/5/3
丟出及攔截異常 丟出異常時會立即離開 try 區塊,此時會結束宣告在 try 區塊中的所有自動物件,所以不能丟出指向 try 區塊之區域物件的異常物件指標 try 丟出異常時,會複製異常物件,所以異常物件必需是可以複製的型態,具有 private copy constructor 的類別物件不能用於異常 2019/5/3
未處理的異常 若 try 區塊的任何 catch 區塊都沒有處理 try 區塊丟出的異常時,則會呼叫標準函式庫函式 terminate(),此函式呼叫已定義的預設結束處理函式,此函式再呼叫標準函式庫函式 abort() 可使用 set_terminate(),用自己的函式取代預設結束處理函式 2019/5/3
未處理的異常 設定自己的預設結束處理函式如下: void myHandler() { // Do something exit(1); } terminate_handler pOldHandler = set_terminate(myHandler); 2019/5/3
未處理的異常 void myHandler(); int main() { /* 一些程式碼 (以 terminate() 當結束處理函式) */ terminate_handler pOldHandler = set_terminate(myHandler); /* 一些程式碼 (以 myHandler() 當結束處理函式)*/ set_terminate(pOldHandler); } 2019/5/3
未處理的異常 set_terminate 的函式宣告是 terminate_handler set_terminate(terminate_handle); terminate_handle 定義在 exception 標準標頭檔 typedef void (*terminate_handler)(); 2019/5/3
引起異常的程式碼 在函式中丟出異常,若此函式未攔截此異常,則此異常會傳給上一層的呼叫函式;若此層的函式也沒有攔截異常,則會再傳給更上一層的呼叫函式,直至異常被 catch 為止。最後仍未被 catch 的異常會呼叫 terminate()。 因此在 try 區塊中的函式若有丟出異常,可被接下來的 catch 區塊處理。 2019/5/3
巢狀 try 區塊 try 區塊中可以有巢狀的 try & catch 區塊,若內層的 catch 無法攔截內層的異常時,外層的 catch 區塊可以攔截並處理之 範例 7.2 2019/5/3
作為異常的類別物件 你可以丟出任何種類的類別物件作為異常 範例 7.3 當丟出異常物件時,事件處理的順序是先複製物件 (產生暫存的物件),然後終結原始的物件,然後將副本傳遞給攔截處理程序。我們會希望是以參考值傳遞,必免複製再次發生 2019/5/3
Catch 處理程序和異常的匹配 當匹配參數 (被攔截) 型態和異常 (被丟出) 型態時,下面是匹配的條件 ‧參數型態和異常型態相同,不管 const ‧參數型態是異常類別型態的直接或間接基礎 類別,或是異常型態的直接或間接基礎類 別的參考值,忽略 const ‧異常和參數是指標,而且異常型態可自動轉 換為參數型態,忽略 const 2019/5/3
Catch 處理程序和異常的匹配 對應於上述的匹配規則,在同一類別的階層架構中,對於異常型態若有數個處理程序,則最後衍生的類別型態必需先出現,最基本的類別型態最後出現 範例 7.4 範例 7.5 (注意 catch 區塊的參數型別必需是參考值的原因) 2019/5/3
重新丟出異常 處理程序攔截異常時,它可以重新丟出此異常使外層 try 區塊的處理程序可以攔截之 重新丟出目前異常的敘述只包含關鍵字 throw,不需要丟出運算式 從內層 try 區塊重新丟出異常時,內層 try 區塊的其他處理程序不可以攔截之 重新丟出異常不會複製現有的異常物件 (範例 7.6 可說明此重要性) 2019/5/3
攔截所有的異常 可用刪節號 (3 個句點) 作為 catch 區塊的參數,攔截所有的異常 catch(...) { // Code to handle any exception } 範例 7.7 2019/5/3