C++异常处理
1. C++异常优势:
C++的异常更加自由. C++可以抛出任意类型的异常,(基本类型,自定义类型,系统提供的特定异常类类型); 而java只能抛出系统提供的异常,或者继承于系统提供的异常基类的自定义类型异常.
2. C++异常处理结构
try {
可能产生异常的代码
if(异常) throw 异常;
}
catch(异常情况1) {
异常处理
}
catch(异常情况...){
异常处理
}
catch(异常情况n) {
异常处理
}
3. 异常处理的过程:
(1) 异常异常: 抛出时会建议一个临时的异常对象
(2) 匹配catch中的异常
(3) 如果匹配成功,利用临时对象,初始化catch的形参
(4) 释放临时对象,进行异常处理.
4. 默认处理异常函数:
(1) 当抛出的异常,未被catch捕获时,程序会调用C++库提供的ternimate函数,该函数会调用abort函数将程序异常中止.
如下代码:
1 #include <iostream> 2 #include <stdio.h> 3 #include <string> 4 #include <typeinfo> 5 #include <errno.h> 6 7 using namespace std; 8 9 int main(void) 10 { 11 int a = 10; 12 int b = 0; 13 int c = 0; 14 15 try{ 16 if(0 == b) throw " 异常,除数为0"; 17 c = a/b; 18 } 19 catch (int ex) { 20 cout<<ex<<endl; 21 } 22 //抛出异常为 const char * 没有匹配的catch 23 catch (char *ex) { 24 cout<<ex<<endl; 25 } 26 printf("程序继续执行\n"); 27 28 return 0; 29 }
程序运行结果如下:
(2)当然,我们可以对tenimate函数进行重写,来自定义异常处理操作.
a. 重写原理: 将 自定义的无返回值,无参函数 通过注册函数复制给 terminate函数指针变量
b. 注册函数: terminate_handler pold_exhandler = set_terminate(new handler);
c. 返回值: 注册函数返回i值是旧terminate函数的地址. 通过这个返回值可以还原旧的terminate函数
代码如下:
1 #include <iostream> 2 #include <stdio.h> 3 #include <stdlib.h> 4 #include <string> 5 #include <typeinfo> 6 #include <errno.h> 7 8 using namespace std; 9 10 void new_terminate() { 11 cout << "新的terminate函数" << endl; 12 exit(1);//正常结束 13 } 14 15 int main(void) 16 { 17 int a = 10; 18 int b = 0; 19 int c = 0; 20 terminate_handler old_terminate = NULL; 21 old_terminate = set_terminate(new_terminate); 22 23 try{ 24 if(0 == b) throw " 异常,除数为0"; 25 c = a/b; 26 } 27 catch (int ex) { 28 cout<<ex<<endl; 29 } 30 catch (char *ex) { 31 cout<<ex<<endl; 32 } 33 printf("程序继续执行\n"); 34 35 return 0; 36 }
程序运行结果如下:
(3) catch(...)
使用省略号作为参数,默认匹配所有类型异常,就好比switch中的default.
5. 系统异常与C++代码主动抛出异常的区别
系统异常有os 抛出,发送信号给进程,我们虽然可以通过linux下信号不活函数处理异常,.但却会破坏程序的可移植性.
c++则是通过提前的异常判断并使用throw主动抛出异常,然后自定义的处理异常
6. catch块中异常匹配的问题
catch形参类型与抛出的异常类型之间的类型匹配
(1)基本类型类型
要求类异常型完全一致时才能匹配上,const>会参与匹配。
(2)类类型
进行类类型异常的匹配时,会涉及自动类型的转换,如果出现以下情况时, 异常都会匹配成功,但const不会参与匹配。
a. 形参类型与抛出的异常类型完全相同,匹配成功,const不参与匹配。
b. 形参类型是抛出异常类型的基类,匹配成功,const不参与匹配。
c. 形参类型是抛出异常类型的基类的引用,匹配成功.
7.函数异常抛出限制
(1) throw() 不能抛出任何类型的异常
(2) throw(异常类型列表) 只允许抛出 异常列表中异常,以及其派生异常
如下代码:
#include <iostream> using namespace std; int division(int a, int b) throw() { try { //if(0 == b) throw DividZeroFPException("除0异常"); if(0 == b) throw 1; return a/b; } catch (float ex) { cout << "内层异常\n" << endl; throw ex;//重新抛出异常 } } int main(void) { int a = 10; int b = 0; int c = 0; try { division(a, b); } catch (int ex) { cout << "外层异常" << endl; } return 0; }
运行结果:
分析: 函数中异常匹配不成功 int!= float ,所以向外抛出异常,但是函数规定throw() 限制向外抛异常,所以调用terminate函数默认处理.
8.多适应系统自定义异常类以及自定义其派生类
从exception派生自定义异常类有一个非常大的好处就是,异常类的继承结构很规范和统一,如果子程序中定义了非常多的异常基类的话,程序异常类型的管理很混乱,不利于使用一个基类统一捕获所有派生类异常。