异常处理

来源:互联网 发布:网络上门服务电话 编辑:程序博客网 时间:2024/06/03 18:18

抛出异常

当一段程序中发现错误数据,但是该程序不知道如何处理时,可以抛出异常。在C++中,用throw来抛出异常。语法如下:

throw 错误信息;

在上面语句中,throw是关键字,该语句用于检测是否产生异常。例如,当除数为0时,抛出异常。例如:

[cpp] view plaincopyprint?
  1. #include<iostream>  
  2. using namespace std;  
  3. int main()  
  4. {  
  5.     int a,b;  
  6.     cout<<"请输入两个整数:"<<endl;  
  7.     cin>>a>>b;  
  8.     if(b==0)  
  9.       throw b;//抛出异常   
  10.     else  
  11.       cout<<"a/b= "<<a/b<<endl;  
  12.     system("pause");  
  13.     return 0;  
  14. }  

上面程序中抛出异常,有错误信息提示。但是如果只有异常抛出,程序将中途退出,这也是具体程序设计中不允许的,为此C++引入了异常的捕获和处理机制。

捕获异常

如果一个函数抛出异常,它必须能被捕获和处理。在C++中提供了try...catch语句来捕获异常,其中,try和catch分别用于定义异常和定义异常处理。定义异常是将可能产生错误的语句放在try语句块中。其格式是:

[cpp] view plaincopyprint?
  1. try  
  2.   
  3. {  
  4.   
  5.   可能产生错误的语句  
  6.   
  7. }  
通常,异常处理是放在try语句块后的由若干个catch语句组成的程序,其格式是:

[cpp] view plaincopyprint?
  1. catch(异常类型声明1)  
  2.   
  3. {  
  4.   
  5.     异常处理语句块1  
  6.   
  7. }  
  8.   
  9. catch(异常类型声明2)  
  10.   
  11. {  
  12.   
  13.     异常处理语句块2  
  14.   
  15. }  
  16.   
  17. ...  
  18.   
  19. catch(异常类型声明n)  
  20.   
  21. {  
  22.   
  23.      异常处理语句块n  
  24.   
  25. }  

定义异常处理是将异常处理的语句放在catch语句块中,以便异常被传递来时处理。try后面至少有一个catch语句块。一旦某个异常被抛出,异常处理机制将会按照 书写catch语句块的代码顺序依次寻找匹配的语句。一旦找到一个相匹配语句,则像调用函数一样进入到该处理器里进行处理。

注意:在查找匹配catch期间,找到的catch不必使与异常最匹配的那个catch,相反会选中第一个找到的可以处理该异常的catch。因此,在catch子句列表中,最特殊的catch必须最先出现。catch与switch不同,不需要在每个case块的后面加break以中断后面程序的执行。在c++程序中,当抛出异常后,寻找匹配的catch子句有固定的过程:逆着程序函数的调用链返回,称为栈展开(Stack Unwinding)。当try中的语句出现异常时,程序跳过try语句块中异常句后面的语句(但析构函数仍然执行),直接执行catch中的语句。

例1:

[cpp] view plaincopyprint?
  1. #include<iostream>  
  2. using namespace std;  
  3. void func1(int n)  
  4. {  
  5.      if(1==n)  
  6.      {  
  7.              cout<<"func1 抛出异常"<<endl;  
  8.              throw 1;  
  9.      }  
  10. }  
  11. void func2(int n)  
  12. {  
  13.      if(2==n)  
  14.      {  
  15.        cout<<"func2 抛出异常"<<endl;  
  16.        throw 2;          
  17.      }  
  18. }  
  19.   
  20. int main()  
  21. {  
  22.  for(int i=1;i<3;i++)  
  23.  {  
  24.   try{  
  25.       func1(i);  
  26.       func2(i);  
  27.       }  
  28.   catch(int)  
  29.   {  
  30.     cout<<"捕捉到Int类型异常"<<endl;  
  31.   }  
  32.  }  
  33.  system("pause");      
  34.  return 0;  
  35. }  

可以看出,上述程序中函数func1和函数func2都可以抛出int类型的异常,因此只有一个Int类型的异常处理。整个try块在for循环之内,因此异常的抛出不影响for循环的运行。

例2:下面程序求一元二次议程的实根,要求加上异常处理,判断b*b-4*a*c是否大于0,成立则求个实根,否则要求重新输入,实现代码如下。

[cpp] view plaincopyprint?
  1. #include<iostream>  
  2. #include<math.h>  
  3. using namespace std;  
  4. double sqrt_delta(double d)  
  5. {  
  6.  if(d<0)  
  7.    throw 1;  
  8.   return sqrt(d);         
  9. }   
  10. double delta(double a,double b,double c)  
  11. {  
  12.   double d=b*b-4*a*c;  
  13.   return sqrt_delta(d);  
  14. }  
  15. int main()  
  16. {   
  17.   double a,b,c;  
  18.   cout<<"请输入a,b,c的值"<<endl;  
  19.   cin>>a>>b>>c;  
  20.   while(true)  
  21.   {  
  22.     try  
  23.     {  
  24.       double d=delta(a,b,c);  
  25.       cout<<"x1: "<<(d-b)/(2*a)<<endl;  
  26.       cout<<"x2: "<<-(b+d)/(2*a)<<endl;  
  27.       break;  
  28.     }  
  29.     catch(int)  
  30.     {  
  31.       cout<<"delta<0,请重新输入a,b,c"<<endl;  
  32.       cin>>a>>b>>c;   
  33.     }  
  34.   }  
  35.   system("pause");  
  36.   return 0;  
  37. }  

catch语句后的参数(即数据类型)需要与throw语句后的表达式数据类型相同。

例3:定义一个异常处理类,该类需能捕获错误类型并返回,在主函数中当用户输入整数1时发生异常,并调用类的成员函数进行异常处理。

[cpp] view plaincopyprint?
  1. #include<iostream>  
  2. #include<string>  
  3. using namespace std;  
  4. class myError  
  5. {  
  6.  private:  
  7.          string sz_error;  
  8.  public:  
  9.         myError(string sz)  
  10.         {  
  11.          this->sz_error = sz;  
  12.         }  
  13.         string what()  
  14.         {return sz_error;}  
  15. };  
  16. int main()  
  17. {  
  18.     int i;  
  19.     cin>>i;  
  20.     try  
  21.     {  
  22.      if(1==i)  
  23.        throw myError("error");  
  24.     }  
  25.     catch(myError e)  
  26.     {  
  27.      cout<<"Error: "<<e.what()<<endl;  
  28.     }  
  29.     system("pause");  
  30.     return 0;  
  31. }  

例4:

[cpp] view plaincopyprint?
  1. #include<iostream>  
  2. using namespace std;  
  3. int Div(int x,int y)  
  4. {  
  5.  if(0==y)  
  6.    throw y;  
  7.  return x/y;  
  8. }  
  9. int main()  
  10. {  
  11.  try  
  12.  {  
  13.   cout<<"7/3= "<<Div(7,3)<<endl;  
  14.   cout<<"9/0= "<<Div(9,0)<<endl;  
  15.   cout<<"8/4= "<<Div(8,4)<<endl;  
  16.  }  
  17.  catch(int)  
  18.  {  
  19.   cout<<"Exception of dividing zero"<<endl;  
  20.  }  
  21.  cout<<"Fine"<<endl;  
  22.  system("pause");  
  23.  return 0;  
  24. }  

上例中,try语句块中,在异常句后面的语句被跳过,直接执行catch及catch后面的语句。

例5

[cpp] view plaincopyprint?
  1. #include<iostream>  
  2. using namespace std;  
  3. void func(int n)  
  4. {  
  5.  try  
  6.  {  
  7.   if(n)  
  8.     throw n;  
  9.   else   
  10.     throw "it is 0";  
  11.   }  
  12.  catch(int i)  
  13.  {cout<<"INT exception : "<<i<<endl;}  
  14.  catch(const char *s)  
  15.  {cout<<"char* exception : "<<s<<endl;}       
  16. }  
  17. int main()  
  18. {  
  19.     func(10);  
  20.     func(0);  
  21.     func(100);  
  22.     system("pause");  
  23.     return 0;  
  24. }  
原创粉丝点击