VC程序设计第十章.ppt
![资源得分’ title=](/images/score_1.gif)
![资源得分’ title=](/images/score_1.gif)
![资源得分’ title=](/images/score_1.gif)
![资源得分’ title=](/images/score_1.gif)
![资源得分’ title=](/images/score_05.gif)
《VC程序设计第十章.ppt》由会员分享,可在线阅读,更多相关《VC程序设计第十章.ppt(31页珍藏版)》请在淘文阁 - 分享文档赚钱的网站上搜索。
1、第十章第十章 异常处理异常处理大型和十分复杂的程序往往会产生一些很难查找的甚至是大型和十分复杂的程序往往会产生一些很难查找的甚至是无法避免的运行时错误。无法避免的运行时错误。当发生运行时错误时,不能简单地结当发生运行时错误时,不能简单地结束程序运行,而是退回到任务的起点,指出错误,并由用户决束程序运行,而是退回到任务的起点,指出错误,并由用户决定下一步工作定下一步工作。面向对象的异常处理(面向对象的异常处理(exception handling)机制是机制是C+语言用以解决这个问题的有力工具。语言用以解决这个问题的有力工具。函数执行时,放在函数执行时,放在try(测试)程序块(测试)程序块中的
2、任何类型的数据对中的任何类型的数据对象发生异常,都可被象发生异常,都可被throw块块抛出,随即抛出,随即沿调用链退回沿调用链退回,直到,直到被被catch块块捕获,并在此执行捕获,并在此执行异常处理异常处理,报告出现的异常等情,报告出现的异常等情况。从抛出到捕获,应将各嵌套调用函数残存在栈中的自动况。从抛出到捕获,应将各嵌套调用函数残存在栈中的自动对象、自动变量和现场保护内容等进行清除。如果已退到入对象、自动变量和现场保护内容等进行清除。如果已退到入口函数还未捕获则由口函数还未捕获则由abort()来终结入口函数。来终结入口函数。异常处理在异常处理在C+编程中已经普遍采用,成为提高程序健壮性
3、编程中已经普遍采用,成为提高程序健壮性的重要手段之一。的重要手段之一。第十章第十章 异常处理异常处理10.1 异常的概念异常的概念 10.3 捕获异常捕获异常 10.2 异常处理的机制异常处理的机制 10.5 异常规范异常规范 10.7 C+标准库异常类标准库异常类 层次结构层次结构 10.6 异常和继承异常和继承 10.4 异常的重新抛出异常的重新抛出 和和catch_all子句子句 10.1 异常的概念异常的概念 这里所讲的这里所讲的异常(异常(exception)是程序可能检测到是程序可能检测到 的,运行时不正常的情况的,运行时不正常的情况,如存储空间耗尽、数组越,如存储空间耗尽、数组越
4、 界、被界、被0除等等,可以预见可能发生在什么地方,但除等等,可以预见可能发生在什么地方,但是无法确知怎样发生和何时发生。特别在一个大型的程序(软是无法确知怎样发生和何时发生。特别在一个大型的程序(软件)中,程序各部分是由不同的小组编写的,它们由公共接口件)中,程序各部分是由不同的小组编写的,它们由公共接口连起来,错误可能就发生在相互的配合上,也可能发生在事先连起来,错误可能就发生在相互的配合上,也可能发生在事先根本想不到的个别的条件组合上。根本想不到的个别的条件组合上。本章介绍的技术,尽管是为大型软件工程开发所发展的,但是它在本章介绍的技术,尽管是为大型软件工程开发所发展的,但是它在标准标准
5、C+中已经成为一个标准的技术,在任何规模的程序中都可以中已经成为一个标准的技术,在任何规模的程序中都可以使用。使用。C+提供了一些内置的语言特性来产生(提供了一些内置的语言特性来产生(raise)或抛出)或抛出(throw)异常,用以通知)异常,用以通知“异常已经发生异常已经发生”,然后由预先安排的,然后由预先安排的程序段来捕获(程序段来捕获(catch)异常,并对它进行处理。这种机制可以在)异常,并对它进行处理。这种机制可以在C+程序的两个无关(往往是独立开发)的部分进行程序的两个无关(往往是独立开发)的部分进行“异常异常”通信。通信。由程序某一部分引发了另一部分的异常,这一异常可回到引起异
6、常由程序某一部分引发了另一部分的异常,这一异常可回到引起异常的部分去处理(沿着程序函数的调用链)。这也是分清处理责任的的部分去处理(沿着程序函数的调用链)。这也是分清处理责任的好办法。好办法。10.2 异常处理的机制异常处理的机制不再是一测到栈满或空就退出程序了,而是抛出一个异常。不再是一测到栈满或空就退出程序了,而是抛出一个异常。template void Stack:Push(const T&data)if(IsFull()throw pushOnFull(data);/注意加了括号注意加了括号,是构造一个无名对象是构造一个无名对象 elements+top=data;templateT
7、Stack:Pop()if(IsEmpty()throw popOnEmpty();return elementstop-;注意注意pushOnFull是是类类,C+要求抛出的必须是对象要求抛出的必须是对象,所以必须有,所以必须有“()”,即,即调用构造函数建立一个对象调用构造函数建立一个对象。异常并非总是类对象,。异常并非总是类对象,throw表达式也表达式也可以抛出任何类型的对象,如枚举、整数等等。但最常用的是类对象。可以抛出任何类型的对象,如枚举、整数等等。但最常用的是类对象。throw表达式表达式抛出异常抛出异常为异常处理的为异常处理的第一步第一步。在堆栈的压栈和出栈操作中在堆栈的压栈
8、和出栈操作中发生错误而抛出的异常,理所当然地应由调用堆栈的程序来处理。发生错误而抛出的异常,理所当然地应由调用堆栈的程序来处理。首先,在首先,在C+中异常往往用类(中异常往往用类(class)来实现,以栈为例,异常)来实现,以栈为例,异常类声明如下类声明如下:class popOnEmpty.;/栈空异常栈空异常class pushOnFull.;/栈满异常栈满异常10.2 异常处理的机制异常处理的机制请看下面的程序段给出请看下面的程序段给出try块与块与catch子句的关系:子句的关系:int main()int a9=1,2,3,4,5,6,7,8,9,b9=0,i;stackistack
9、(8);try for(i=0;i9;i+)istack.Push(ai);istack.PrintStack();catch(pushOnFull)cerr”栈满栈满”endl;try for(i=0;i9;i+)bi=istack.Pop();catch(popOnEmpty)cerr”栈空栈空”endl;for(i=0;i9;i+)coutbit;coutendl;return 0;这里有两个这里有两个try块,分别对应压栈与出栈;也有两个块,分别对应压栈与出栈;也有两个catch子句(子句(catch clause),分别处理压栈时的栈满和出栈时的栈空。),分别处理压栈时的栈满和出栈时
10、的栈空。在在C+中建立异常抛出与异常处理之间有一整套程序设计的机制。中建立异常抛出与异常处理之间有一整套程序设计的机制。首先采用关键字首先采用关键字try,构成一个,构成一个try块块(try block),它包含了),它包含了抛抛出异常的语句出异常的语句。当然也可以是包含了这样的。当然也可以是包含了这样的调用语句调用语句,该语句所,该语句所调用的函数中有能够抛出异常的语句。调用的函数中有能够抛出异常的语句。10.2 异常处理的机制异常处理的机制程序按下列规则控制:程序按下列规则控制:1如如果果没没有有异异常常发发生生,继继续续执执行行try块块中中的的代代码码,与与try块块相相关关联联 的
11、的catch子句被忽略,程序正常执行,子句被忽略,程序正常执行,main()返回返回0。2当当第第一一个个try块块在在for循循环环中中抛抛出出异异常常,则则该该for循循环环退退出出,try块块也也退退出出,去去执执行行pushOnFull异异常常的的catch子子句句。istack.PrintStack()不再执行,被忽略。不再执行,被忽略。3如如果果第第二二个个try块块调调用用Pop()抛抛出出异异常常,则则退退出出for和和try块块,去去执行执行popOnEmpty异常的异常的catch子句。子句。4当某条语句抛出异常时,跟在该语句后面的语句将被跳过。程当某条语句抛出异常时,跟在
12、该语句后面的语句将被跳过。程序执行权交给处理异常的序执行权交给处理异常的catch子句,如果没有子句,如果没有catch子句能够处子句能够处理异常,则交给理异常,则交给C+标准库中定义的标准库中定义的terminate()。由由catch字句捕获并处理异常是字句捕获并处理异常是第二步第二步。注意与。注意与catch语句分别语句分别匹配匹配的是在压栈和出栈成员函数模板中的的是在压栈和出栈成员函数模板中的throw语句,一个抛出语句,一个抛出pushOnFull类的无名对象,另一个抛出类的无名对象,另一个抛出popOnEmpty类的无名类的无名对象。对象。在编制程序时有一条在编制程序时有一条惯例惯
13、例:把正常执行的程序与异常处理两部分分隔开:把正常执行的程序与异常处理两部分分隔开来,这样使代码更易于跟随和维护。在上例中,我们可以把两个来,这样使代码更易于跟随和维护。在上例中,我们可以把两个try块合块合成一个,而把两个成一个,而把两个catch子句都放在函数最后。子句都放在函数最后。10.2 异常处理的机制异常处理的机制int main()try int a9=1,2,3,4,5,6,7,8,9,b9=0;stack istack(8);.;return 0;catch(popOnEmpty)cerr”栈空栈空”endl;return 1;catch(pushOnFull)cerr”栈满
14、栈满”endl;return 2;一个函数一个函数try块把一组块把一组catch子句同一个函数体相关联。如果函数子句同一个函数体相关联。如果函数体中的语句抛出一个异常,则考虑跟在函数体后面的处理代码来体中的语句抛出一个异常,则考虑跟在函数体后面的处理代码来处理该异常。函数处理该异常。函数try块对构造函数尤其有用。块对构造函数尤其有用。catch子句必须在子句必须在try块之后;而块之后;而try块后必须紧跟一个或多个块后必须紧跟一个或多个catch子句,目的是对发生的异常进行处理。子句,目的是对发生的异常进行处理。catch的括号中只能有一个的括号中只能有一个类型,当类型与抛掷异常的类型匹
15、配时,称该类型,当类型与抛掷异常的类型匹配时,称该catch子句捕获了一子句捕获了一个异常,并转到该块中进行异常处理。个异常,并转到该块中进行异常处理。把程序的正常处理代码和异常处理代码分离的最清楚的方法是定把程序的正常处理代码和异常处理代码分离的最清楚的方法是定义函数义函数try块(块(function try block),但但VC+6.0不支持。这种方不支持。这种方法是把整个函数包括在法是把整个函数包括在try块中:块中:10.3 捕获异常捕获异常catch子句由三部分组成:关键字子句由三部分组成:关键字catch、圆括号中的异常声、圆括号中的异常声明以及复合语句中的一组语句。明以及复合
16、语句中的一组语句。*注意这注意这不是函数不是函数,所以圆括号中不是形参,而是一个异常类型声明,可,所以圆括号中不是形参,而是一个异常类型声明,可以是类型也可以是对象。看一看以是类型也可以是对象。看一看catch子句的使用就可知它与函数的不同子句的使用就可知它与函数的不同了:它只有一个子句,没有定义和调用之分。使用时由系统按规则自动在了:它只有一个子句,没有定义和调用之分。使用时由系统按规则自动在catch子句列表中匹配。至少从逻辑上讲,没有函数的定义与调用。子句列表中匹配。至少从逻辑上讲,没有函数的定义与调用。catch子句可以包含返回语句(子句可以包含返回语句(return),也可不包含返回
17、语句。包含返),也可不包含返回语句。包含返回语句,则整个程序结束。而不包含返回语句,则执行回语句,则整个程序结束。而不包含返回语句,则执行catch列表之后的下列表之后的下一条语句。一条语句。异常声明中也可以是一个对象声明。以栈为例。当栈满时,要求在异常对异常声明中也可以是一个对象声明。以栈为例。当栈满时,要求在异常对象中象中保存不能被压入到栈中的值保存不能被压入到栈中的值,这时,这时,pushOnFull类可定义如下:类可定义如下:template class pushOnFull T _value;public:pushOnFull(T i):_value(i)/或写为或写为pushOnF
18、ull(T i)_value=i;T value()return _value;新的私有数据成员新的私有数据成员_value保存那些不能被压入栈中的值。该值即调用构造函保存那些不能被压入栈中的值。该值即调用构造函数时的实参。数时的实参。10.3 捕获异常捕获异常这这样样在在catch子子句句中中,要要取取得得_value,须须调调用用pushOnFull中中的的成成员员函数函数value():catch(pushOnFull eObj)cerr”栈满栈满”eObj.value()”未压入栈未压入栈”endl;return 1;在在catch子句的异常声明中声明了对象子句的异常声明中声明了对象e
19、Obj,用它来调用用它来调用pushOnFull类的对象成员函数类的对象成员函数value()。异常对象是在抛出点被创异常对象是在抛出点被创建,与建,与catch子句是否显式要求创建一个异常对象无关,该对象总是子句是否显式要求创建一个异常对象无关,该对象总是存在,在存在,在catch子句中只是为了调用异常处理对象的成员函数才声明子句中只是为了调用异常处理对象的成员函数才声明为对象,不用类。为对象,不用类。对应在对应在throw表达式中,构造抛出对象也要有实参:表达式中,构造抛出对象也要有实参:throw pushOnFull(data);/data即即Push(const&data)中的参数中
20、的参数data*catch子句异常声明中采用对象只是一种形式。甚至异常并非一个类对象子句异常声明中采用对象只是一种形式。甚至异常并非一个类对象时,也可以用同样的格式,比如异常为一枚举量,这时就等效于按值传递,时,也可以用同样的格式,比如异常为一枚举量,这时就等效于按值传递,而不是调用类对象的公有成员。而不是调用类对象的公有成员。10.3 捕获异常捕获异常catch子子句句的的异异常常声声明明与与函函数数参参数数声声明明类类似似,可可以以是是按按值值传传送送,也也可可以以是是按按引引用用传传递递。如如果果catch子子句句的的异异常常声声明明改改为为引用声明,则引用声明,则catch子句可以直接
21、引用由子句可以直接引用由throw表达式创建表达式创建的的异异常常对对象象,而而不不必必创创建建自自己己的的局局部部拷拷贝贝。对对大大型型类类对对象象减减少少不不必必要要的的拷拷贝贝是是很很有有意意义义的的,所所以以对对于于类类类类型型的的异异常常,其其异异常常声声明明最最好好也也是是被声明为引用。如:被声明为引用。如:catch(pushOnFull&eObj)cerr”栈满栈满”eObj.value()”未压栈未压栈”endl;return 1;使用引用类型的异常声明,使用引用类型的异常声明,catch子句能够修改异常对象,但仅仅是子句能够修改异常对象,但仅仅是异常对象本身,正常程序部分的
22、量并不会被修改。与一般类对象不同,异常对象本身,正常程序部分的量并不会被修改。与一般类对象不同,实际上异常对象处理完后,生命期也就结束了。实际上异常对象处理完后,生命期也就结束了。只有需要重新抛出异只有需要重新抛出异常(在下一节中讨论),修改操作才有意义。常(在下一节中讨论),修改操作才有意义。下面的讨论展现了下面的讨论展现了C+异常处理的不可替代的技术。异常处理的不可替代的技术。寻找匹配的寻找匹配的catch子句有固定子句有固定的过程:如果的过程:如果throw表达式位表达式位于于try块中,则检查与块中,则检查与try块相块相关联的关联的catch子句列表,看是子句列表,看是否有一个子句能
23、够处理该异常,否有一个子句能够处理该异常,有匹配的,则该异常被处理;有匹配的,则该异常被处理;找不到匹配的找不到匹配的catch子句,则子句,则在主调函数中继续查找。如果在主调函数中继续查找。如果一个函数调用在退出时带有一一个函数调用在退出时带有一个被抛出的异常未能处理,而个被抛出的异常未能处理,而且这个调用位于一个且这个调用位于一个try块中,块中,则检查与该则检查与该try块相关联的块相关联的catch子句列表,看是否有一子句列表,看是否有一个子句匹配,有,则处理该异个子句匹配,有,则处理该异常;没有,则查找过程在该函常;没有,则查找过程在该函数的主调函数中继续进行。即数的主调函数中继续进
24、行。即这个查找过程逆着嵌套的函数这个查找过程逆着嵌套的函数调用链向上继续,直到找到处调用链向上继续,直到找到处理该异常的理该异常的catch子句。子句。只要只要遇到第一个匹配的遇到第一个匹配的catch子句,子句,就会进入该就会进入该catch子句,进行子句,进行处理,查找过程结束。处理,查找过程结束。10.3 捕获异常捕获异常在栈异常处理的例子中,对在栈异常处理的例子中,对popOnEmpty,首先应在,首先应在istack的成员函数的成员函数Pop()中找,因为中找,因为Pop()中的中的throw表达式表达式没有在没有在try块中,所以块中,所以Pop()带着一个异常退出。下一步是检带着
25、一个异常退出。下一步是检查调用查调用Pop()的函数,这里是的函数,这里是main(),在,在main()中对中对Pop()的的调用位于一个调用位于一个try块中,则可用与该块中,则可用与该try块关联的块关联的catch子句列子句列表中的某一个来处理,找到第一个表中的某一个来处理,找到第一个popOnEmpty类型异常声类型异常声明的明的catch子句,并进入该子句进行异常处理。子句,并进入该子句进行异常处理。因发生异常而逐步退出复合语句和函数定义,被称为因发生异常而逐步退出复合语句和函数定义,被称为栈展栈展开(开(stack unwinding)。这是异常处理的核心技术。这是异常处理的核心
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- VC 程序设计 第十
![提示](https://www.taowenge.com/images/bang_tan.gif)
限制150内