异常处理的一些说明
{
被检查的语句;
}
catch(异常信息的类型[变量名])
{
进行异常处理的语句;
}
cout<<a<<endl; //不能插入其他语句
catch(double)
但是在一个try-catch结构中,可以只有try块而无catch块。即只检查而不处理,把catch处理块放在其他函数中。
3.try块和catch块中必须有用花括号括起来的复合语句,即使花括号内只有一条语句,也不能省略花括号。
try { }
catch(double) { }
catch(int) { }
cathc(char) { }
catch(double)
catch只检查所捕获异常信息的类型,而不检查它们的值,例如a,b,c都是double类型,虽然它们的值不同,但在throw语句中写throw a,throw b,throw c,作用类型均相同。因此如果需要检测多个不同的异常信息,应当由throw抛出不同类型的异常信息。
异常信息可以是C++系统预定义的标准类型,也可以是用户自定义的类型(如结构体或类)。如果由throw抛出的信息属于该类型或者子类型,则catch与throw二者匹配,catch捕获该异常信息。
catch还可以指定变量名,如
catch(double d)
此时如果throw抛出的异常信息是double型的变量a,则catch在捕获异常信息a的同时,还使得d获得a的值,或者说d得到a的一个拷贝。什么时候需要这样做呢?有时候希望捕获异常信息时,还能利用throw抛出的值,如
catch(double d)
{
cout<<"thorow"<<d;
}
6.如果在catch子句中没有指定异常信息的类型,而用了删节号"...",则表示它可以捕捉任何类型时的异常信息,如
catch(...)
{
cout<<"ERROR!"<<endl;
}
它能捕捉所有类型的异常信息,并输出"ERROR!"
这种catch句子 应放在try-catch结构中的最后,相当于"其他"。如果把它作为第一个catch子句,则后面的catch子句都不起作用。
7. try-catch结构可以与throw出现在同一个函数中,也可以不在同一个函数中。当throw抛出异常信息后,首先在本函数中寻找与之匹配的catch,如果在本层无try-catch结构或找不到与之匹配的catch,就转到其上一层去处理,如果上一层也无try-catch结构或找不到与之匹配的catch,则再转到更上一层的try-catch结构去处理,也就是说转到离开出现异常最近的try-catch结构去处理。
8.在某些情况下,在throw语句中可以不包括表达式,如果在catch块中包含“throw”:
catch(int)
{
//其他语句
throw;
}
表示“我不处理这个异常,请上级处理”。此时catch块把当前的异常信息再次抛出,给上一层的catch块处理。
9.如果throw抛出的异常信息找不到与之匹配的catch块,那么系统就会调用一个系统函数terminate,使程序终止运行。
10.C++允许在声明函数时,可列出可能抛出的异常类型,如
double triangle(double,double,double) throw(double)
表示triangle函数只能抛出double类型的异常信息,如果写成
double triangle(double,double,double) throw(double,int,char,float)
则表示triangle函数只限于抛出double,int,char,float类型的异常信息。
11.如果在try块(或try块中调用的函数)中定义了类对象,在建立该对象时要调用构造函数。在执行try块(包括在try块中调用其他函数)的过程中如果发生了异常,此时流程立即离开try块(如果是在try块调用的函数中发生异常,则流程首先离开该函数,回到调用它的try块处,然后流程再从try块中跳出转到catch处理块)。这样的流程就有可能离开该对象的作用域而转到其他函数,因而应事先做好结束对象前的清理工作, C++的异常处理机制会在throw语句抛出异常信息被catch捕获时,对有关的局部对象进行析构(调用类对象的析构函数), 析构对象的顺序与构造的顺序相反,然后执行与异常信息匹配的catch块中的语句。
运行结果:
一、异常处理的语法
throw语句的语法: throw 表达式;try-catch的结构为:
try{
被检查的语句;
}
catch(异常信息的类型[变量名])
{
进行异常处理的语句;
}
二、.详细说明
1.被检测的部分必须放在try块中,否则不起作用。
2.try块和catch块作为一个整体出现,catch块是try-catch结构中的一部分,必须紧跟在try块之后,不能单独使用,在两者之间也不能插入其他语句,例如:
try{
//do something
}cout<<a<<endl; //不能插入其他语句
catch(double)
{
//do something
}但是在一个try-catch结构中,可以只有try块而无catch块。即只检查而不处理,把catch处理块放在其他函数中。
3.try块和catch块中必须有用花括号括起来的复合语句,即使花括号内只有一条语句,也不能省略花括号。
try { }
catch(double) { }
catch(int) { }
cathc(char) { }
靠catch类型来匹配
catch(double)
catch只检查所捕获异常信息的类型,而不检查它们的值,例如a,b,c都是double类型,虽然它们的值不同,但在throw语句中写throw a,throw b,throw c,作用类型均相同。因此如果需要检测多个不同的异常信息,应当由throw抛出不同类型的异常信息。
异常信息可以是C++系统预定义的标准类型,也可以是用户自定义的类型(如结构体或类)。如果由throw抛出的信息属于该类型或者子类型,则catch与throw二者匹配,catch捕获该异常信息。
catch还可以指定变量名,如
catch(double d)
此时如果throw抛出的异常信息是double型的变量a,则catch在捕获异常信息a的同时,还使得d获得a的值,或者说d得到a的一个拷贝。什么时候需要这样做呢?有时候希望捕获异常信息时,还能利用throw抛出的值,如
catch(double d)
{
cout<<"thorow"<<d;
}
6.如果在catch子句中没有指定异常信息的类型,而用了删节号"...",则表示它可以捕捉任何类型时的异常信息,如
catch(...)
{
cout<<"ERROR!"<<endl;
}
它能捕捉所有类型的异常信息,并输出"ERROR!"
这种catch句子 应放在try-catch结构中的最后,相当于"其他"。如果把它作为第一个catch子句,则后面的catch子句都不起作用。
7. try-catch结构可以与throw出现在同一个函数中,也可以不在同一个函数中。当throw抛出异常信息后,首先在本函数中寻找与之匹配的catch,如果在本层无try-catch结构或找不到与之匹配的catch,就转到其上一层去处理,如果上一层也无try-catch结构或找不到与之匹配的catch,则再转到更上一层的try-catch结构去处理,也就是说转到离开出现异常最近的try-catch结构去处理。
8.在某些情况下,在throw语句中可以不包括表达式,如果在catch块中包含“throw”:
catch(int)
{
//其他语句
throw;
}
表示“我不处理这个异常,请上级处理”。此时catch块把当前的异常信息再次抛出,给上一层的catch块处理。
9.如果throw抛出的异常信息找不到与之匹配的catch块,那么系统就会调用一个系统函数terminate,使程序终止运行。
10.C++允许在声明函数时,可列出可能抛出的异常类型,如
double triangle(double,double,double) throw(double)
表示triangle函数只能抛出double类型的异常信息,如果写成
double triangle(double,double,double) throw(double,int,char,float)
则表示triangle函数只限于抛出double,int,char,float类型的异常信息。
11.如果在try块(或try块中调用的函数)中定义了类对象,在建立该对象时要调用构造函数。在执行try块(包括在try块中调用其他函数)的过程中如果发生了异常,此时流程立即离开try块(如果是在try块调用的函数中发生异常,则流程首先离开该函数,回到调用它的try块处,然后流程再从try块中跳出转到catch处理块)。这样的流程就有可能离开该对象的作用域而转到其他函数,因而应事先做好结束对象前的清理工作, C++的异常处理机制会在throw语句抛出异常信息被catch捕获时,对有关的局部对象进行析构(调用类对象的析构函数), 析构对象的顺序与构造的顺序相反,然后执行与异常信息匹配的catch块中的语句。
三、在异常处理中处理析构函数
代码示例:
//异常处理中的析构问题
#include<iostream>
#include<string>
using namespace std;
class Student
{
public:
Student(int n,string nam)
{
cout<<"constructor-"<<n<<endl;
num=n;
name=nam;
}
~Student()
{
cout<<"destructor-"<<num<<endl;
}
void get_data();
private:
int num;
string name;
};
void Student::get_data()
{
if(num==0) throw num;
else
cout<<num<<" "<<name<<endl;
cout<<"in get_data()"<<endl;
}
void fun()
{
Student stdu1(101,"lanzhihui");
stdu1.get_data();//正常执行
Student stdu2(0,"wangdan");
stdu2.get_data();//出现异常,先析构stud2,再析构stud1,最后处理异常
Student stdu3(102,"wangqian");//不再构造此对象,转去执行catch后面的语句
stdu3.get_data();
}
int main()
{
cout<<"main begin"<<endl;
cout<<"call fun()"<<endl;
try
{
fun();
}
catch(int n)
{
cout<<"num="<<n<<",error!"<<endl;
}
cout<<"main end"<<endl;
system("pause");
return 0;
}
运行结果: