现在结合程序分析怎样进行异常处理。
(1) 首先把可能出现异常的、需要检查的语句或程序段放在try后面的花括号中。
(2) 程序开始运行后,按正常的顺序执行到try块,开始执行try块中花括号内的语句。如果在执行try块内的语句过程中没有发生异常,则catch子句不起作用,流程转到catch子句后面的语句继续执行。
(3) 如果在执行try块内的语句(包括其所调用的函数)过程中发生异常,则throw运算符抛出一个异常信息。throw抛出异常信息后,流程立即离开本函数,转到其上一级的函数(main 函数)
throw抛出什么样的数据由程序设计者自定,可以是任何类型的数据。
(4) 这个异常信息提供给try-catch结构,系统会寻找与之匹配的catch子句。
(5) 在进行异常处理后,程序并不会自动终止,继续执行catch子句后面的语句。
由于catch子句是用来处理异常信息的,往往被称为catch异常处理块或catch异常处理器。
 
下面讲述异常处理的语法。
throw语句一般是由throw运算符和一个数据组成的,其形式为
throw 表达式;
try-catch的结构为
try
      {被检查的语句}
catch(异常信息类型 [变量名])
      {进行异常处理的语句}
说明:
(1) 被检测的函数必须放在try块中,否则不起作用。
(2) try块和catch块作为一个整体出现,catch块是try-catch结构中的一部分,必须紧跟在try块之后,不能单独使用,在二者之间也不能插入其他语句。但是在一个try-catch结构中,可以只有try块而无catch块。即在本函数中只检查而不处理,把catch处理块放在其他函数中。
(3) trycatch块中必须有用花括号括起来的复合语句,即使花括号内只有一个语句,也不能省略花括号。
(4) 一个try-catch结构中只能有一个try块,但却可以有多个catch块,以便与不同的异常信息匹配。
(5) catch后面的圆括号中,一般只写异常信息的类型名,
catch(double)
catch只检查所捕获异常信息的类型,而不检查它们的值。因此如果需要检测多个不同的异常信息,应当由throw抛出不同类型的异常信息。
异常信息可以是C++系统预定义的标准类型,也可以是用户自定义的类型(如结构体或类)。如果由throw抛出的信息属于该类型或其子类型,则catchthrow二者匹配,catch捕获该异常信息。
catch还可以有另外一种写法,即除了指定类型名外,还指定变量名,如
catch(double d)
此时如果throw抛出的异常信息是double型的变量a,则catch在捕获异常信息a的同时,还使d获得a的值,或者说d得到a的一个拷贝。什么时候需要这样做呢?有时希望在捕获异常信息时,还能利用throw抛出的值,如
catch(double d)
  {cout<<throw <<d;}
这时会输出d的值(也就是a)。当抛出的是类对象时,有时希望在catch块中显示该对象中的某些信息。这时就需要在catch的参数中写出变量名(类对象名)
(6) 如果在catch子句中没有指定异常信息的类型,而用了删节号“…”,则表示它可以捕捉任何类型的异常信息,如
catch(…) {cout<<OK<<endl;}
它能捕捉所有类型的异常信息,并输出″OK
这种catch子句应放在try?catch结构中的最后,相当于其他。如果把它作为第一个catch子句,则后面的catch子句都不起作用。
(7) try?catch结构可以与throw出现在同一个函数中,也可以不在同一函数中。当throw抛出异常信息后,首先在本函数中寻找与之匹配的catch,如果在本函数中无try?catch结构或找不到与之匹配的catch,就转到离开出现异常最近的try?catch结构去处理。
(8) 在某些情况下,在throw语句中可以不包括表达式,如
throw;
表示我不处理这个异常,请上级处理
(9) 如果throw抛出的异常信息找不到与之匹配的catch块,那么系统就会调用一个系统函数terminate,使程序终止运行。
2 在函数嵌套的情况下检测异常处理。
这是一个简单的例子,用来说明在try块中有函数嵌套调用的情况下抛出异常和捕捉异常的情况。请自己先分析以下程序。
#include <iostream>
using namespace std;
int main( )
{void f1( );
 try
  {f1( );}//调用f1( )
 catch(double)
  {cout<<OK0!<<endl;}
 cout<<end0<<endl;
 return 0;
}
void f1( )
{void f2( );
 try
  {f2( );}                      //调用f2( )
 catch(char)
  {cout<<OK1!;}
 cout<<end1<<endl;
}
void f2( )
{void f3( );
 try
 {f3( );}                      //调用f3( )
 catch(int)
 {cout<<Ok2!<<endl;}
 cout<<end2<<endl;
}
void f3( )
{double a=0;
 try
  {throw a;}               //抛出double类型异常信息
 catch(float)
  {cout<<OK3!<<endl;}
 cout<<end3<<endl;
}
 
3种情况分析运行情况:
(1)       执行上面的程序。图1为有函数嵌套时异常处理示意图。
1
程序运行结果如下:
OK0!(在主函数中捕获异常)
end0                (执行主函数中最后一个语句时的输出)
(2) 如果将f3函数中的catch子句改为catch(double),而程序中其他部分不变,则程序运行结果如下:
OK3!(f3函数中捕获异常)
end3                   (执行f3函数中最后一个语句时的输出)
end2                   (执行f2函数中最后一个语句时的输出)
end1                   (执行f1函数中最后一个语句时的输出)
end0                   (执行主函数中最后一个语句时的输出)
(3) 如果在此基础上再将f3函数中的catch块改为
catch(double)
  {cout<<OK3!<<endl;throw;}
程序运行结果如下:
OK3!(f3函数中捕获异常)
OK0!                  (在主函数中捕获异常)
end0                  (执行主函数中最后一个语句时的输出)