1、第8章 异常处理面向对象技术与Visual C+-第8章2本章主要内容异常处理概述异常处理概述 异常处理的语法异常处理的语法应用实例应用实例面向对象技术与Visual C+-第8章3异常处理概述异常处理概述 异常处理是由程序设计语言提供的运行时刻错误处理异常处理是由程序设计语言提供的运行时刻错误处理的一种方式。的一种方式。程序运行中的有些错误是可以预料但不可避免的,这程序运行中的有些错误是可以预料但不可避免的,这是要力争做到允许用户排除环境错误,继续运行程序;是要力争做到允许用户排除环境错误,继续运行程序;至少要给出适当的提示信息。至少要给出适当的提示信息。传统错误处理方法大致可以分为传统错误
2、处理方法大致可以分为返回码机制返回码机制和和全局变全局变量量两种。两种。面向对象技术与Visual C+-第8章41.1.返回码机制返回码机制 这种处理错误的方法比较实用和简单,这也是经常采取这种处理错误的方法比较实用和简单,这也是经常采取的手段之一。对于小型的程序来说这种异常处理机制的缺点的手段之一。对于小型的程序来说这种异常处理机制的缺点暴露不明显,对于一个需要多人开发的软件程序来说,它的暴露不明显,对于一个需要多人开发的软件程序来说,它的弊端就非常明显!弊端就非常明显!因为对于一个模块的实现者来说有的人返回值因为对于一个模块的实现者来说有的人返回值0 0代表错误;代表错误;有的人返回值有
3、的人返回值0 0代表正确,非代表正确,非0 0代表错误。解决方法可以用一代表错误。解决方法可以用一致性的条文来控制。通常的,这些返回码就在一个公共的致性的条文来控制。通常的,这些返回码就在一个公共的.h.h文件中以宏的形式存在。这样暂时解决了团队之间的一致性,文件中以宏的形式存在。这样暂时解决了团队之间的一致性,但是这些都但是这些都不是标准,兼容性太差不是标准,兼容性太差。对于如此多的返回码要。对于如此多的返回码要分别解释各自的意义,从调用者的角度来说,需要分别对返分别解释各自的意义,从调用者的角度来说,需要分别对返回码进行检查来处理异常,这样的代码往往就显得非常的臃回码进行检查来处理异常,这
4、样的代码往往就显得非常的臃肿,大大降低了可读性。肿,大大降低了可读性。面向对象技术与Visual C+-第8章52.全局变量全局变量 通过用一个全局变量来表示一次操作是否成通过用一个全局变量来表示一次操作是否成功。这个方法在多线程中就非常头痛。另外在功。这个方法在多线程中就非常头痛。另外在每次处理完异常之后就要复位这个变量,如果每次处理完异常之后就要复位这个变量,如果忘记这个步骤,就会引起其他操作的误解。忘记这个步骤,就会引起其他操作的误解。面向对象技术与Visual C+-第8章6异常处理实现异常处理实现 C+语言提供对处理异常情况的内部支持。语言提供对处理异常情况的内部支持。try,thr
5、ow和和catch语句就是语句就是C+语言中用于实现语言中用于实现异常处理的机制。异常处理的机制。有了有了C+异常处理,程序可以向更高的执行上异常处理,程序可以向更高的执行上下文传递意想不到的事件,从而使程序能更好下文传递意想不到的事件,从而使程序能更好地从这些异常事件中恢复过来。地从这些异常事件中恢复过来。面向对象技术与Visual C+-第8章7例例8-2 示例使用异常处理来处理错误。示例使用异常处理来处理错误。#include void main()int divisor,dividend;double quotient;try /异常测试块定义异常测试块定义coutdividend;c
6、outdivisor;if(divisor=0)throw dividend;/抛出异常抛出异常quotient=dividend/double(divisor);coutThe result is:quotientendl;面向对象技术与Visual C+-第8章8catch(int)/捕获异常捕获异常 coutThe divisor is zero,worry!endl;coutEnd of program.endl;面向对象技术与Visual C+-第8章9异常处理的语法异常处理的语法 try-throw-catch是抛出和捕获异常的基本机制。是抛出和捕获异常的基本机制。Throw语句抛
7、出异常(一个值),语句抛出异常(一个值),catch捕获异常。捕获异常。抛出一个异常后,抛出一个异常后,try块会终止,转而执行块会终止,转而执行catch块中的语句。块中的语句。catch块结束之后,会继续执行块结束之后,会继续执行catch块之后的语块之后的语句(前提是句(前提是catch块中没有终止程序或者执行另外块中没有终止程序或者执行另外一些特殊的操作)。一些特殊的操作)。如果如果try块中没有抛出异常,那么在块中没有抛出异常,那么在try块结束之后,块结束之后,程序将从程序将从catch块之后的语句继续执行。换言之,块之后的语句继续执行。换言之,如果没有抛出异常,如果没有抛出异常,
8、catch块会被忽略。块会被忽略。面向对象技术与Visual C+-第8章10try块块 如果在函数内直接用如果在函数内直接用throw抛出一个异常(或在函抛出一个异常(或在函数调用时抛出一个异常),将在异常抛出时退出数调用时抛出一个异常),将在异常抛出时退出函数。如果不想在异常抛出时退出函数,可以在函数。如果不想在异常抛出时退出函数,可以在函数体内创建一个特殊块用于解决程序中潜在的函数体内创建一个特殊块用于解决程序中潜在的错误,在这个块中可以测试各种错误发生的可能错误,在这个块中可以测试各种错误发生的可能性,通常称为测试块,它由关键字性,通常称为测试块,它由关键字try引导。引导。其定义格式
9、如下:其定义格式如下:try 面向对象技术与Visual C+-第8章11抛出异常抛出异常 通常将抛出的值直接称为一个异常,所以执行通常将抛出的值直接称为一个异常,所以执行throw语句就称为抛出异常,可以抛出任意类语句就称为抛出异常,可以抛出任意类型的一个值。型的一个值。其定义的格式如下:其定义的格式如下:throw 执行执行throw语句时,外围的语句时,外围的try块就会停止执行。块就会停止执行。如果如果try块之后跟有一个合适的块之后跟有一个合适的catch块,那么块,那么控制权就会转交给那个控制权就会转交给那个catch块。一般说来,块。一般说来,throw语句几乎肯定要嵌入一个分支
10、语句(比语句几乎肯定要嵌入一个分支语句(比如如if语句)中语句)中。面向对象技术与Visual C+-第8章12捕获异常捕获异常 抛出一个异常后,外围的抛出一个异常后,外围的try块会停止执行,并块会停止执行,并开始执行另一个部分的语句,也就是开始执行另一个部分的语句,也就是catch块。块。执行执行catch的过程称为捕获异常或者异常处理。的过程称为捕获异常或者异常处理。一个异常被抛出以后,最终应该由某个一个异常被抛出以后,最终应该由某个catch块来处理。块来处理。面向对象技术与Visual C+-第8章13 一般说来,一般说来,catch块参数主要完成两件事情:块参数主要完成两件事情:q
11、catch块参数前要加一个类型名,表示块参数前要加一个类型名,表示catch块块可以捕获什么类型的异常抛出值;可以捕获什么类型的异常抛出值;qcatch块参数为捕获的异常抛出值指定了一个名块参数为捕获的异常抛出值指定了一个名称,所以在称,所以在catch块中,又可以对这个异常抛出块中,又可以对这个异常抛出值进行相应的处理。值进行相应的处理。面向对象技术与Visual C+-第8章14 catch块的语法定义如下:块的语法定义如下:catch(type_name variable_name)需要注意的是,如果需要注意的是,如果try块中没有异常被抛出,块中没有异常被抛出,那么在那么在try块正常
12、结束后,程序从块正常结束后,程序从catch块之后块之后的语句继续执行。换言之,如果没有抛出异常,的语句继续执行。换言之,如果没有抛出异常,catch块会被忽略。块会被忽略。面向对象技术与Visual C+-第8章15还可以定义一个能捕获任意类型的异常的处理器:还可以定义一个能捕获任意类型的异常的处理器:catch()cout“an exception was throm”endl;可捕获所有的异常,同时就不能有参数,因此可捕获所有的异常,同时就不能有参数,因此不可能知道所接收到得异常为何种类型。不可能知道所接收到得异常为何种类型。面向对象技术与Visual C+-第8章16例例8-3 示例捕
13、捉多个异常。示例捕捉多个异常。#include#include class Negativenumberpublic:Negativenumber();Negativenumber(char*take_it_to_catch_block);char*get_message();private:char message30;面向对象技术与Visual C+-第8章17class Dividebyzero;/定义异常类定义异常类int main()int dividend,divisor;double portion;trycoutdividend;if(dividend0)throw Negat
14、ivenumber(dividend);coutdivisor;if(divisor0)throw Negativenumber(divisor);if(divisor!=0)portion=dividend/(double)divisor;else throw Dividebyzero();coutThe result is:portionendl;面向对象技术与Visual C+-第8章18catch(Negativenumber e)coutCannot have a negative numberof “e.get_message()endl;catch(Dividebyzero)co
15、utThe divisor is zero.worry!endl;coutEnd of program.endl;return 1;面向对象技术与Visual C+-第8章19Negativenumber:Negativenumber()Negativenumber:Negativenumber(char*take_it_to_catch_block)strcpy(message,take_it_to_catch_block);char*Negativenumber:get_message()return message;说明:说明:Class Dividebyzero;这个异常类没有成员变量
16、和成员函数,但它很有用。抛出这个异常类没有成员变量和成员函数,但它很有用。抛出Dividebyzero类的一个对象,会激活相应的类的一个对象,会激活相应的catch块。块。面向对象技术与Visual C+-第8章20Class Dividebyzero;这个异常类没有成员变量和成员函数,但它很有用。抛出这个异常类没有成员变量和成员函数,但它很有用。抛出Dividebyzero类的一个对象,会激活相应的类的一个对象,会激活相应的catch块。块。面向对象技术与Visual C+-第8章218.2.2异常处理中的构造与析构异常处理中的构造与析构1.C+异常处理的真正能力,不仅在于它能够处理各种不异
17、常处理的真正能力,不仅在于它能够处理各种不同类型的异常,还在于它具有为异常抛投前构造的所有局同类型的异常,还在于它具有为异常抛投前构造的所有局部对象自动调用析构函数的能力。部对象自动调用析构函数的能力。2.如果如果catch子句的异常类型声明是一个值参数,则其初始子句的异常类型声明是一个值参数,则其初始化方式是复制被抛投的异常对象。如果化方式是复制被抛投的异常对象。如果catch子句的异常子句的异常类型声明是一个引用,则其初始化方式是使该引用指向异类型声明是一个引用,则其初始化方式是使该引用指向异常对象。常对象。3.将从对应的将从对应的try块开始到异常被抛投之间构造(且尚未析块开始到异常被抛
18、投之间构造(且尚未析构)的所有自动对象进行析构。构)的所有自动对象进行析构。面向对象技术与Visual C+-第8章22例 异常处理时的析构#include void MyFunc(void);class Expt public:Expt();Expt();const char*ShowReason()const return Expt类异常。;class Demo public:Demo();Demo();Demo:Demo()cout 构造 Demo.endl;Demo:Demo()cout 析构 Demo.endl;void MyFunc()Demo D;cout 在MyFunc()中抛
19、掷Expt类异常。endl;throw Expt();int main()cout 在main函数中。endl;try cout 在try块中,调用MyFunc()。endl;MyFunc();catch(Expt E)cout 在catch异常处理程序中。endl;cout 捕获到Expt类型异常:;cout E.ShowReason()endl;catch(char*str)cout 捕获到其它的异常:str endl;cout 回到main函数。从这里恢复执行。endl;return 0;程序运行时输出程序运行时输出:在在main函数中。函数中。在在try块中,调用块中,调用MyFunc
20、()。)。构造构造 Demo.在在MyFunc()中抛掷)中抛掷Expt类异常。类异常。析构析构 Demo.在在catch异常处理程序中。异常处理程序中。捕获到捕获到Expt类型异常:类型异常:Expt类异常。类异常。回到回到main函数。从这里恢复执行。函数。从这里恢复执行。面向对象技术与Visual C+-第8章27例例8-4 示例处理不同类型的异常。要求可以触发不同类型异常并显示抛示例处理不同类型的异常。要求可以触发不同类型异常并显示抛 出异常时的程序执行情况。出异常时的程序执行情况。#include class CExceptpublic:CExcept(int Excode)m_Ex
21、code=Excode;int GetExcode()return m_Excode;private:int m_Excode;面向对象技术与Visual C+-第8章28void main()char ch;trycoutAt begining of try block.endl;coutch;if(ch=y|ch=Y)throw Error description.;coutch;if(ch=y|ch=Y)throw 1;面向对象技术与Visual C+-第8章29coutch;if(ch=y|ch=Y)throw CExcept(5);coutch;if(ch=y|ch=Y)throw
22、3.1416;coutAt end of try block(no exception thrown).endl;面向对象技术与Visual C+-第8章30catch(char*errorMsg)coutchar*exception thrown;exception message:;couterrorMsgendl;catch(int ErrorCode)coutint exception thrown;exception code:ErrorCodeendl;面向对象技术与Visual C+-第8章31catch(CExcept Except)coutclass CExcept exception thrown;exception code:;coutExcept.GetExcode()endl;catch(.)coutUnknown type of exception thrown.endl;coutAfter last catch block.endl;