重抛异常
若某个异常在处理过程中发现需要更外层的结构对它进行处理,则可以通过在catch结构中调用throw重新抛出异常,将当前异常传递到外部的try-catch结构中,这样就允许多个处理程序访问该异常。重抛异常时只能从catch语句块或从catch块中的调用函数中完成,该异常将不会被同一个catch捕捉,而是传递到外层的try-catch结构中。
除了可以采用普通抛出异常的方式重抛异常,还可单独使用throw关键字完成异常重抛。下面分别介绍这两种重抛异常的方式。
1、采用普通方式重抛异常
和前面介绍的抛出异常的语法相同,在catch块中可以采用“throw 异常值;”的方式重抛异常。
接下来通过一个案例来说明如何通过普通方式重抛异常,如例1所示。
例1
1 #include <iostream>
2 #include <string>
3 using namespace std;
4 int int_div(int a, int b) //实现整数相除的函数
5 {
6 if (b == 0){
7 throw 0;
8 }
9 return a / b;
10 }
11 void exception_handler(int n1, int n2)
12 {
13 try{
14 cout << "Maybe exception code:" << endl;
15 cout << n1 << "/" << n2 << " = "
16 << int_div(n1, n2) << endl; //除数非零显示相除结果
17 cout << "in try, after div!" << endl;
18 }
19 catch (int n) //捕捉参数为整型的异常
20 {
21 cout << "exception:div "
22 << n << "!" << endl; //异常处理代码
23 throw n; //重新抛出异常
24 }
25 }
26 int main()
27 {
28 int int_n1, int_n2; //定义两个整型变量
29
30 while (1){ //循环多次读取数据,完成相除操作
31 cout << "Please input two integers:";
32 cin >> int_n1 >> int_n2;
33
34 try{
35 exception_handler(int_n1, int_n2);
36 }
37 catch (int)
38 {
39 cout << "outter try-catch!" << endl; //接收第23行重抛的异常
40 }
41 }
42 return 0;
43 }
若除数为0,程序运行结果如图1所示。
图1 例1运行结果
例1仍然完成的是除零异常的检测及捕捉。第11-25行的exception_handler()函数中的try-catch结构用于检测及捕捉除零异常,catch结构捕捉异常后,代码第23行又重新抛出该异常,则代码第34-40行的外层try-catch结构会捕捉该异常进行处理。
2、采用标准语法重抛异常
对于重抛异常,除了和原来相同的语法形式之外,还可使用标准语法形式:
throw; //throw后没有异常值或异常对象
若抛出的异常是类对象,则通常采用标准语法,例如定义异常类exception的派生类derive_exception,代码如下所示:
class derive_exception: public exception
{
…
};
在内层try结构中抛出派生类异常:
try
{
try
{
…
throw derive_exception(); //抛出异常派生类对象
}
catch (const exception &e) //使用基类引用作为catch参数
{
cout << “Can not handle the exception” << endl;
throw e; //重抛基类对象异常
//throw; //采用标准语法重抛异常
}
}
catch (…) //处理异常
{
…
cout << “Handle exception” << endl;
}
上述代码中,内层的try结构内抛出了派生类对象异常,但接收异常的catch结构却使用了基类形参,catch结构中又将异常按照基类类型重新抛出,则会导致原有派生类异常对象的部分信息丢失,解决办法是,采用异常重抛的标准语法格式重抛异常。
另外还有一点需要说明的是,采用标准语法抛出的是当前捕获的异常,而不是新的拷贝;采用“throw e;”方式抛出异常需要进行对象拷贝,拷贝动作带来了对象的构造与析构,会降低工作效率。