基础备忘:异常处理

抛出异常

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

throw 错误信息;

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

#include<iostream>
using namespace std;
int main()
{
    int a,b;
    cout<<"请输入两个整数:"<<endl;
    cin>>a>>b;
    if(b==0)
      throw b;//抛出异常 
    else
      cout<<"a/b= "<<a/b<<endl;
    system("pause");
    return 0;
}

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

捕获异常

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

try

{

  可能产生错误的语句

}
通常,异常处理是放在try语句块后的由若干个catch语句组成的程序,其格式是:

catch(异常类型声明1)

{

    异常处理语句块1

}

catch(异常类型声明2)

{

    异常处理语句块2

}

...

catch(异常类型声明n)

{

     异常处理语句块n

}

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

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

例1:

#include<iostream>
using namespace std;
void func1(int n)
{
     if(1==n)
     {
             cout<<"func1 抛出异常"<<endl;
             throw 1;
     }
}
void func2(int n)
{
     if(2==n)
     {
       cout<<"func2 抛出异常"<<endl;
       throw 2;        
     }
}

int main()
{
 for(int i=1;i<3;i++)
 {
  try{
      func1(i);
      func2(i);
      }
  catch(int)
  {
    cout<<"捕捉到Int类型异常"<<endl;
  }
 }
 system("pause");    
 return 0;
}

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

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

#include<iostream>
#include<math.h>
using namespace std;
double sqrt_delta(double d)
{
 if(d<0)
   throw 1;
  return sqrt(d);       
} 
double delta(double a,double b,double c)
{
  double d=b*b-4*a*c;
  return sqrt_delta(d);
}
int main()
{ 
  double a,b,c;
  cout<<"请输入a,b,c的值"<<endl;
  cin>>a>>b>>c;
  while(true)
  {
    try
    {
      double d=delta(a,b,c);
      cout<<"x1: "<<(d-b)/(2*a)<<endl;
      cout<<"x2: "<<-(b+d)/(2*a)<<endl;
      break;
    }
    catch(int)
    {
      cout<<"delta<0,请重新输入a,b,c"<<endl;
      cin>>a>>b>>c; 
    }
  }
  system("pause");
  return 0;
}

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

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

#include<iostream>
#include<string>
using namespace std;
class myError
{
 private:
         string sz_error;
 public:
        myError(string sz)
        {
         this->sz_error = sz;
        }
        string what()
        {return sz_error;}
};
int main()
{
    int i;
    cin>>i;
    try
    {
     if(1==i)
       throw myError("error");
    }
    catch(myError e)
    {
     cout<<"Error: "<<e.what()<<endl;
    }
    system("pause");
    return 0;
}

例4:

#include<iostream>
using namespace std;
int Div(int x,int y)
{
 if(0==y)
   throw y;
 return x/y;
}
int main()
{
 try
 {
  cout<<"7/3= "<<Div(7,3)<<endl;
  cout<<"9/0= "<<Div(9,0)<<endl;
  cout<<"8/4= "<<Div(8,4)<<endl;
 }
 catch(int)
 {
  cout<<"Exception of dividing zero"<<endl;
 }
 cout<<"Fine"<<endl;
 system("pause");
 return 0;
}

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

例5

#include<iostream>
using namespace std;
void func(int n)
{
 try
 {
  if(n)
    throw n;
  else 
    throw "it is 0";
  }
 catch(int i)
 {cout<<"INT exception : "<<i<<endl;}
 catch(const char *s)
 {cout<<"char* exception : "<<s<<endl;}     
}
int main()
{
    func(10);
    func(0);
    func(100);
    system("pause");
    return 0;
}


  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值