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派生自定义异常类有一个非常大的好处就是,异常类的继承结构很规范和统一,如果子程序中定义了非常多的异常基类的话,程序异常类型的管理很混乱,不利于使用一个基类统一捕获所有派生类异常。           

posted @ 2016-08-29 19:10  邬峙  阅读(506)  评论(0编辑  收藏  举报