c++ primer plus 第15章友,異常和其他:異常,15.3.7 其他異常特性
c++ primer plus 第15章友,異常和其他:異常,15.3.7 其他異常特性
15.3.7 其他異常特性
雖然 throw-catch 機制類似于函數參數和函數返回機制,但還是有些不同之處。其中之一是函數 fun()中的返回語句將控制權返回到調用 fun()的函數,但throw 語句將控制權向上返回到第一個這樣的函數:包含能夠捕獲相應異常的try-catch 組合。例如,在程序清單15.12中,當函數hmeans()引發異常時,控制權
將傳遞給函數 means();然而,當 gmean()引發異常時,控制權將向上傳遞到 main()。另一個不同之處是,引發異常時編譯器總是創建一個臨時拷貝,即使異常規范和catch塊中指定的是引用。例如,請看下面的代碼:
class problem(...);
void super()throw(problem)
{...if (oh_no)problem oops;//construct objectthrow oops;// throw it...}
try{
super();
catch(problem&p)
//statements
}
p將指向 oops的副本而不是 oops本身。這是件好事,因為函數 super()執行完畢后,oops 將不復存在。順便說一句,將引發異常和創建對象組合在一起將更簡單:
throw problem();//construct and throw default problem object
您可能會問,既然 throw 語句將生成副本,為何代碼中使用引用呢?畢竟,將引用作為返回值的通常原因是避免創建副本以提高效率。答案是,引用還有另一個重要特征:基類引用可以執行派生類對象。假設有一組通過繼承關聯起來的異常類型,則在異常規范中只需列出一個基類引用,它將與任何派生類對象匹配。假設有一個異常類層次結構,并要分別處理不同的異常類型,則使用基類引用將能夠捕獲任何異常對象;而使用派生類對象只能捕獲它所屬類及從這個類派生而來的類的對象。引發的異常對象將被第一個與之匹配的 catch 塊捕獲。這意味著catch 塊的排列順序應該與派生順序相反:
class bad 1{...};
class bad 2:public bad 1(...};
class bad 3:public bad 2{...};
...
void duper()
{
i f(oh_no)throw bad 1();
if (rats)throw bad 2();
if (drat)throw bad 3();
}
try{
duper();
catch(bad 3 &be)// statements
catch(bad 2 &be)(//statements
catch(bad 1 &be)// statements
}
如果將 bad 1&處理程序放在最前面,它將捕獲異常bad_1、bad2和 bad 3;通過按相反的順序排列,bad3異常將被bad3&處理程序所捕獲,
提示:如果有一個異常類繼承層次結構,應這樣排列 catch 塊:將捕獲位于層次結構最下面的異常類的 catch語句放在最前面,將捕獲基類異常的catch 語句放在最后面。
通過正確地排列 catch塊的順序,讓您能夠在如何處理異常方面有選擇的余地。然而,有時候可能不知道會發生哪些異常。例如,假設您編寫了一個調用另一個函數的函數,而您并不知道被調用的函數可能引發哪些異常。在這種情況下,仍能夠捕獲異常,即使不知道異常的類型。方法是使用省略號來表示異常類型,從而捕獲任何異常:
catch(...){//statements)// catches any type exception
如果知道一些可能會引發的異常,可以將上述捕獲所有異常的catch塊放在最后面,這有點類似于switch 語句中的 default:
try{
duper();
}
catch(bad 3 &be)//statements
catch(bad 2 &be)//statements
catch(bad 1 &be)// statements
catch(bad hmean &h)
//statement
scatch(..)//statements
//catch whatever is left
可以創建捕獲對象而不是引用的處理程序。在catch語句中使用基類對象時,將捕獲所有的派生類對象,但派生特性將被剝去,因此將使用虛方法的基類版本。