18异常处理

程序执行中需要处理异常:

1.动态分配空间时可能不会成功

2.打开文件可能会失败

3.除法运算时分母可能为0

4.整数相乘可能溢出

5.指针可能越界等情况

 

异常处理方法一:

1.使用选择语句(if…else…)

2.判断异常情况,即时处理

3.正常程序流程和异常处理语句混在一起

4.程序员往往无法专注于正常流程编程

异常处理方法二:

1.使用C++异常处理机制

2.判断异常情况,发现异常后抛出异常

3.正常程序流程和异常处理模块分开

4.程序员可以专注于正常流程编程,异常处理模块稍候编写

 

C++异常处理机制

1.程序在产生错误后抛出异常

2.异常处理模块捕获并处理异常

3.异常处理机制一般无法使程序恢复正常执行

4.可以为程序提供有序的整理操作(如析构对象)

关键字try:出错时产生异常的代码放在try块中

关键字throw:throw语句可以抛出任意类型的异常,包括自定义类型

关键字catch:catch块(异常处理器)捕捉和处理异常

 

注意:

1.一个异常处理器一般只捕捉一种类型的异常

2.try块抛出异常后,程序控制离开try块

3.抛出异常后,程序在try块后面的catch块中逐个搜索合适的异常处理器

4.如果try块没有异常抛出,则程序跳过所有catch块

5.抛出异常之后,程序控制无法返回到抛出点

6.try块可以直接或间接抛出异常

 

示例;
除数为零的异常处理

#include <iostream.h>

 #include <string.h>

 //定义异常类MyException

 class MyException

 {public:

   MyException(char *str)

   {  msg = str;  }

   char * show()

   {  return msg; }

  private:

   char *msg;

 };

//定义除法函数division,除数为0时抛出异常。

double division(int dividend, int divisor)

{  if (divisor == 0)

   //抛出异常对象

   throw MyException(

          "error: divided by zero!");

   return (double)dividend/divisor;

}

main()

 {int a, b;

  double result;

  cout<<"Enter two integers (EOF:end):";

  while (cin>>a>>b) //慎用

  {try

    {result = division(a,b);

     cout<<a<<" / "<<b<<" = "

         <<result<<endl;

    }

   catch (MyException e)

    {cout<<e.show()<<endl;}

   cout<<endl;

   cout<<"Enter two integers (EOF:end):";

  }

return 0;

}

 

 

异常的抛出和传播(一)

1.关键字throw可以带任何类型的操作数(任意表达式),包括自定义类型(如异常对象)

2.异常抛出后,最近匹配的异常处理器捕获该异常

3.如果没有匹配的异常处理器,则系统调用terminate函数,terminate函数默认调用abort函数终止程序的执行

4.抛出异常时,throw语句生成异常数据的一个副本,异常处理器执行完毕后删除

 

示例:抛出各类异常,并捕捉它们

#include <iostream.h>

 main()

 { int a, myint;

   float myfloat;

   double mydouble;

   cout<<"Enter a integer (EOF to end):";

   while (cin>>a) //抛出不同类型的异常

   { try {

         switch(a % 3) {

         case 0:

         //输入整数为3的倍数时抛出整型异常

            myint = a;

            throw myint;

            break;

         case 1: //抛出float类型异常

            myfloat = (float)a;

            throw myfloat;

            break;

         case 2: //抛出double类型异常

            mydouble = a;

            throw mydouble;

            break;

         default:

            break;

         }

      }

    catch (int e) //捕获整型异常

   {cout<<"Integer Exception: "<<e<<endl;

   }     

   catch (float e) //捕获浮点类型异常

   {cout<<"Float Exception: "<<e<<endl;

   }

   catch (double e) //捕获双精度类型异常

   {cout<<"Double Exception: "<<e<<endl;

   }

   cout<<endl;

   cout<<"Enter a integer (EOF to end):";

  }

  return 0;

 }

 

异常的抛出和传播(二)

1.在try块中直接或间接抛出的异常,由其后匹配的catch块捕捉

2.在try块外面抛出的异常将不会被捕捉到,系统会调用terminate函数终止程序的运行

3.发生异常后跳出抛出异常的程序块,并且无法再返回到抛出点

4.异常可以在try块中显式抛出,也可以在其调用的函数中抛出

 

异常的抛出和传播(三)

try块可以嵌套

内层try块抛出异常的传播顺序

(1)先在内层try块后面的catch块中寻找合适的异常处理器

(2)找到则进行处理,异常不再往外传播

(3)如果找不到,则将该异常向外传播,到外层try块后面的catch块中继续寻找

(4)如果异常传播到最外层的try块仍然找不到,则程序调用terminate函数

 

示例:异常传播的例子

#include <iostream.h> 

 int add(int a, int b)

 {int res;

  try  //结果过大过小时都抛出异常

  {res = a + b;

   if (res > 128)   //抛出整型异常

    throw res;

   if (res<0)       //抛出字符串异常

    throw "Negative result!";

  }

  catch (int e) //捕捉整型异常

  {cout<<"The result is too large :“

       <<e<<endl;

   return -1;

  }

  return res; }

main()

 {int a, b, result;

 cout<<"Enter two integers (EOF to end):";

  while (cin>>a>>b)

  {try

   {result = add(a, b);

    if (result >= 0)

     cout<<"The result is "<<result<<endl;

   }

   catch (...) //捕捉传播到外层的所有异常

   {cout<<"Unexpected exception."<<endl;}

   cout<<endl;

   cout<<"Enter a integer (EOF to end):";

  }

return 0;

 }

 

 

异常的捕获和处理

1.异常处理器以关键字catch开始

2.异常处理器能带一个参数(能捕捉的异常类型),参数名可选

3.有参数名时,可以在异常处理器内使用这个参数,该参数只是抛出的异常对象的一个副本  catch (int e){…}

4.没有参数名时,异常对象不从抛出点传递到异常处理器中  catch (int){…}

5.程序按顺序寻找匹配的异常处理器,抛出的异常被第一个类型符合的异常处理器捕获

6.如果内层try块后面没有找到合适的异常处理器,该异常向外传播,到外层try块后面寻找

7.没有被捕获的异常将调用terminate函数,terminate函数默认调用abort函数终止程序执行

8.可以使用set_terminate函数指定terminate函数将调用的函数

9.参数列表中只有省略号的异常处理器能捕捉所有类型的异常catch (...) {语句序列}

10异常处理器的排列顺序,可能会影响异常处理的结果

Visual C++: try后必须跟至少一个catch ; set_terminate有问题

 

满足下面条件之一时,异常被捕捉:

1.异常处理器的参数类型和抛出的异常数据的类型完全相同

2.异常处理器的参数类型是抛出的异常对象的基类

3.异常处理器的参数是基类的指针或引用,抛出的异常数据类型是派生类的指针或引用

4.异常处理器的参数是void*类型的指针,抛出的异常数据类型是某一种类型的指针

5.异常处理器为catch(…)

 

示例:异常捕获的例子

#include <iostream.h>

 //定义基类

 class base

 {public:

   void show()

   {cout<<"Base object."<<endl;}

 };

//定义派生类

 class derived :public base

 {public:

   void show()

   {cout<<"Derived object."<<endl;}

 };

main()

 {int no;

  cout<<"Input a integer please:";

  while(cin>>no)

  {try

   {if ((no % 2) == 0) //抛出基类对象

     throw base();

    else    //抛出派生类对象

     throw derived();

   }

   catch(base b)

   {cout<<"Exception:";

    b.show();

   }

   catch(derived d)

   {cout<<"Exception:";

    d.show();

   }

   cout<<endl<<"Input a integer please:";

  }

  return 0;

 }

posted @ 2018-01-09 17:01  gd_沐辰  阅读(204)  评论(0编辑  收藏  举报