异常处理
来源:互联网 发布:网络上门服务电话 编辑:程序博客网 时间:2024/06/03 18:18
抛出异常
当一段程序中发现错误数据,但是该程序不知道如何处理时,可以抛出异常。在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
- {
- 可能产生错误的语句
- }
- 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;
- }
- 异常处理+异常+处理异常+自定义异常
- 异常处理
- 异常处理
- 异常处理
- 异常处理
- 异常处理
- 异常处理
- 异常处理
- 异常处理
- 异常处理
- 异常处理
- 异常处理
- 异常处理
- 异常处理
- 异常处理
- 异常处理
- 异常处理
- 异常处理
- strlen与sizeof区别
- string类字符串和char*/char[]型型字符串的区别
- Project Euler problem 29
- MyEclipse 9上搭建Android开发环境
- 苦逼三流小公司程序员这半年找工作经历
- 异常处理
- 用Mongos代替驱动来增加副本集的故障切换能力
- linux安装JDK(JDK1.7)
- STL基本范例
- nginx ——redhat5.5 实现负载均衡
- iterator与const_iterator及const iterator区别
- 《黑客与画家》中的只言片语
- (转)c fread()在判断文件结束时需要注意的一些事
- 使用初始化清单和直接在构造函数内初始化成员变量的区别