16.2.2 异常处理程序
异常处理程序由一个或多个catch函数组成,每个catch函数块参数列表只能有一个参数,用于匹配由throw抛出的异常的类型,当try块中调用的函数可能抛出多种类型的异常时,需要多个catch函数形成异常捕获网,捕获所有可能的异常类型。异常处理程序紧接着try块,并且由关键字catch表示,如下所示。
try { 可能抛出异常的一个或多个函数调用 } catch(type1 id1) { 处理type1类型的异常 } catch(type2 id2) { 处理type1类型的异常 } catch(type3 id3) { 处理type1类型的异常 } 程序继续
异常处理程序(catch函数)必须紧跟在try块之后,当某个异常被抛出,异常处理机制会按照catch块的代码顺序依次寻找匹配的catch块,一旦找到一个相匹配的catch块,则系统会认为该异常已得到处理。
除了后面所讲的有继承关系的异常对象外,异常处理机制并不对异常参数类型进行转换。前面讲过,如果try块中抛出的异常没有找到相应的catch块对其进行处理,将会执行系统默认的terminate函数。
注意
最好是把catch函数块的参数写成引用传递,而不是值传递,稍后会作出解释。
有时候可能需要一种能够捕获所有异常的catch块,用省略号(3个点)代替catch块的参数列表就可实现,如下所示。
catch(……) { cout<<"发生异常"<<endl; }
省略号catch块能够捕获任何类型的异常,最好将其放在catch块列表的最后,避免架空其后面的异常处理器。
省略号catch块不接受任何参数,无法得到任何有关异常的信息,作为一个“全能捕获者”,省略号catch块经常用于清理资源并重新抛出所捕获的异常。重新抛出异常是指在一个catch块内部,使用不带参数的throw语句将所捕获的异常重新抛出到更高一层的语境中去处理,如下所示。
catch(……) { cout<<"异常发生"<<endl; //资源释放(稍后会讲到) throw;//重新抛出异常 }
如以下示例代码16.4所示。
代码16.4 省略号catch块和重新抛出异常CatchAll
<———————————文件名:example1604.cpp———————————————-> 01 #include<iostream> 02 #include<cmath>//使用sqrt函数要包含的头文件 03 using namespace std; 04 double calc() 05 { 06 cout<<"请输入一个不小于0的数:"<<endl; 07 double num=-1; 08 cin>>num; 09 if(!cin. good())//输入失败 10 { 11 cin. clear();//清除流状态字 12 cin. sync();//清空流缓冲区 13 throw"错误,输入的不是数字";//抛出字符串型异常 14 } 15 if(num<0)//如果num<0或输入不成功,则抛出字符串类型s 16 throw"错误,请输入一个不小于0的数字";//抛出字符串型异常 17 return sqrt(num); 18 } 19 void keepInput() 20 { 21 double res=0; 22 try//使用try块标记可能发生异常的代码块 23 { 24 res=calc();//正常的函数调用,如果异常发生,将被抛出 25 } 26 catch(……)//捕获try块中抛出所有异常 27 { 28 cout<<"异常重新抛出"<<endl; 29 throw;//重新抛出 30 } 31 cout<<res<<endl;//没有异常发生,输出结果 32 } 33 int main() 34 { 35 while(true)//无限循环,直到break退出 36 { 37 try//使用try块标记可能抛出异常的代码块 38 { 39 keepInput();//函数调用 40 } 41 catch(const char*s) 42 { 43 cout<<s<<endl;//捕捉keepinput函数中重新抛出的异常 44 continue;//继续循环 45 } 46 break;//运算成功,退出 47 } 48 return 0; 49 }
输出结果如下所示。
请输入一个不小于0的数: A 异常重新抛出 错误,输入的不是数字 请输入一个不小于0的数字: -5 异常重新抛出 错误,请输入一个不小于0的数字 请输入一个不小于0的数字: 2 1.41421
【代码解析】在keepinput函数中调用了calc函数,为了处理calc函数中抛出的异常,使用了try+catch块的异常处理机制,在main函数中,对keepinput函数的调用也是通过try+catch异常机制来完成的,代码第26行的keepinput函数中使用了省略号catch块,这将捕获calc函数抛出的所有类型的异常,同时,在keepinput函数中,采用了无参throw将异常重新抛出到更高一层范围内,也就是main函数try块后紧跟的catch块列表,由main函数的catch块来捕捉异常并进行处理。