C++电子课件(下)第十章.ppt
《C++电子课件(下)第十章.ppt》由会员分享,可在线阅读,更多相关《C++电子课件(下)第十章.ppt(41页珍藏版)》请在三一办公上搜索。
1、第十章 异常处理,大型和十分复杂的程序往往会产生一些很难查找的甚至是无法避免的运行时错误。当发生运行时错误时,不能简单地结束程序运行,而是退回到任务的起点,指出错误,并由用户决定下一步工作。面向对象的异常处理(exception handling)机制是C+语言用以解决这个问题的有力工具。,第十章 异常处理,10.1 异常的概念,10.3 栈展开与 异常捕获,10.2 异常处理的机制,10.5异常和继承,10.7 C+标准库异常类 层次结构(选读),10.6异常规范(选读),10.4 异常的重新抛出 和catch_all子句,10.1 异常的概念,异常概念的引入:异常(exception)是程
2、序可能检测到的,运行时不正常的情况,如存储空间耗尽、数组越界、被0除等等。可以预见可能发生在什么地方,但是无法确知怎样发生和何时发生。特别在一个大型的程序(软件)中,程序各部分是由不同的小组编写的,它们由公共接口连起来,错误可能就发生在相互的配合上,也可能发生在事先根本想不到的个别的条件组合上。,10.1 异常的概念,C+提供了一些内置的语言特性来产生(raise)或抛出(throw)异常,用以通知“异常已经发生”,然后由预先安排的程序段来捕获(catch)异常,并对它进行处理。这种机制可以在C+程序的两个无关(往往是独立开发)的部分进行“异常”通信。由程序某一部分引发了另一部分的异常,这一异
3、常可回到引起异常的部分去处理(逆着程序的函数调用链)。,10.2 异常处理的机制,测到栈满或空就抛出异常。template void Stack:Push(const T 注意pushOnFull和popOnEmpty是类,C+要求抛出的必须是对象,所以必须有“()”,即调用构造函数建立一个对象。,异常与异常抛出:以栈为例,异常类声明如下:template class popOnEmpty.;/栈空异常template class pushOnFull.;/栈满异常,10.2 异常处理的机制,throw表达式抛出异常为异常处理的第一步。在堆栈的压栈和出栈操作中发生错误而抛出的异常,理所当然地应
4、由调用堆栈的程序来处理。异常并非总是类对象,throw表达式也可以抛出任何类型的对象,如枚举、整数等等。但最常用的是类对象。,在C+中异常抛出与异常处理之间有一整套程序设计的机制。首先采用关键字try,构成一个try块(try block),它包含了抛出异常的语句。当然也可以是包含了这样的调用语句,该语句所调用的函数中有能够抛出异常的语句。,异常处理机制:,10.2 异常处理的机制,int main()int a9=1,2,3,4,5,6,7,8,9,b9=0,i;stackistack(8);try for(i=0;i)cerr)cerr”栈空”endl;for(i=0;i9;i+)cout
5、bit;coutendl;return 0;,try块与catch子句的关系实例:,10.2 异常处理的机制,由catch字句捕获并处理异常是第二步。注意与catch语句分别匹配的是在压栈和出栈成员函数模板中的throw语句,一个抛出pushOnFull类的无名对象,另一个抛出popOnEmpty类的无名对象。,在编制程序时有一条惯例:把正常执行的程序与异常处理两部分分隔开来,这样使代码更易于跟随和维护。在上例中,我们可以把两个try块合成一个,而把两个catch子句都放在函数最后。,说明:这里有两个try块,分别对应压栈与出栈;也有两个catch子句(catch clause),分别处理压栈
6、时的栈满和出栈时的栈空。,10.2 异常处理的机制,1如果没有异常发生,继续执行try块中的代码,与try块相关联的catch子句被忽略,程序正常执行,main()返回0。2当第一个try块在for循环中抛出异常,则该for循环退出,try块也退出,去执行可处理pushOnFull异常的catch子句。istack.PrintStack()不再执行,被忽略。3如果第二个try块调用Pop()抛出异常,则退出for和try块,去执行可处理popOnEmpty异常的catch子句。4当某条语句抛出异常时,跟在该语句后面的语句将被跳过。程序执行权交给处理异常的catch子句,如果没有catch子句能
7、够处理异常,则交给C+标准库中定义的函数terminate()。,流程控制规则:,10.3 栈展开与异常捕获,catch子句由三部分组成:关键字catch、圆括号中的异常声明以及复合语句中的一组语句。,catch子句不是函数,所以圆括号中不是形参,而是一个异常类型声明,可以是类型也可以是对象。catch子句的使用:它只有一个子句,没有定义和调用之分。使用时由系统按规则自动在catch子句列表中匹配。,catch子句可以包含返回语句(return),也可不包含返回语句。包含返回语句,则整个程序结束。而不包含返回语句,则执行catch列表之后的下一条语句。,catch子句说明:当try块中的语句抛
8、出异常时,系统通过查看跟在其后的catch子句列表,来查找可处理该异常的catch子句。,10.3 栈展开与异常捕获,对应在throw表达式中,构造抛出对象也要有实参:throw pushOnFull(data);/data即Push(const&data)中的参数data,template class pushOnFull T _value;public:pushOnFull(T i):_value(i)/或写为pushOnFull(T i)_value=i;T value()return _value;新的私有数据成员_value保存那些不能被压入栈中的值。该值即调用构造函数时的实参。,c
9、atch子句异常声明探讨:异常声明中可以是一个对象声明。以栈为例,当栈满时,要求在异常对象中保存不能被压入到栈中的值,pushOnFull类可定义如下:,10.3 栈展开与异常捕获,在catch子句中,要取得_value,须调用pushOnFull 中的成员函数value():Catch(pushOnFull eObj)cerr”栈满”eObj.value()”未压入栈”endl;return 1;在catch子句的异常声明中声明了对象eObj,用它来调用pushOnFull类的对象成员函数value()。异常对象是在抛出点被创建,与catch子句是否显式要求创建一个异常对象无关,该对象总是存
10、在,在catch子句中只是为了调用异常处理对象的成员函数才声明为对象,不用类。,*catch子句异常声明中采用对象只是一种形式。甚至异常并非一个类对象时,也可以用同样的格式,比如异常为一枚举量,这时就等效于按值传递,而不是为了调用类对象的公有成员。,10.3 栈展开与异常捕获,catch子句的异常声明与函数参数声明类似,可以是按值传递,也可以是按引用传递。对大型类对象减少不必要的复制是很有意义的,所以对于类类型的异常,其异常声明最好也是被声明为引用。如:,catch(pushOnFull,使用引用类型的异常声明,catch子句能够修改异常对象,但仅仅是异常对象本身,正常程序部分的量并不会被修改
11、。与一般类对象不同,实际上异常对象处理完后,生命期也就结束了。只有需要重新抛出异常(在下一节中讨论),修改操作才有意义。,【例10.1】包含栈满或空异常的完整的程序。,10.3 栈展开与异常捕获,把程序的正常处理代码和异常处理代码分离的最清楚的方法是定义函数try块(Function try Block)。这种方法是把整个函数包括在try块中。,一个函数try块把一组catch子句同一个函数体相关联。如果函数体中的语句抛出一个异常,则考虑跟在函数体后面的处理代码来处理该异常。函数try块对构造函数尤其有用。,【例10.1_1】定义函数try块(Function try Block)。,函数tr
12、y块的使用:,寻找匹配的catch子句:如果throw表达式位于try块中,则检查与try块相关联的catch子句列表,看是否有匹配的子句能够处理该异常;如无匹配的catch子句,则在主调函数中继续查找。如果函数调用在退出时带有一个被抛出的异常未能处理,而且该调用位于一个try块中,则检查与该try块相关联的catch子句列表,看是否有匹配的子句能处理该异常;没有,则查找过程逆着嵌套的函数调用链向上继续,直到找到能处理该异常的catch子句。只要遇到第一个匹配的catch子句,就会进入该catch子句进行处理,查找结束。如最终未找到匹配的字句,则由terminate()处理。,10.3 栈展开
13、与异常捕获,在栈异常处理的例子中,对popOnEmpty,首先应在istack的成员函数Pop()中找,因为Pop()中没有try块,不存在catch子句,所以Pop()带着一个异常退出。下一步是检查调用Pop()的函数,这里是main(),在main()中对Pop()的调用位于一个try块中,则可用与该try块关联的catch子句列表中的某一个来处理,找到第一个popOnEmpty类型异常声明的catch子句,并进入该子句进行异常处理。,栈展开:因发生异常而逐步退出复合语句和函数定义的过程,被称为栈展开(stack unwinding)异常处理的核心技术。,异常对程序的影响通常不仅是在发生异
14、常的那个局部范围中,而且可能逆调用链而上,甚至整个任务。因此,异常处理应该在其对程序影响的终结处进行,甚至是在调用该任务的菜单处进行。,10.3 栈展开与异常捕获,在栈展开期间,在退出的域中有某个局部量是类对象,栈展开过程将自动调用该对象的析构函数,完成资源的释放。所以C+异常处理过程本质上反映的是“资源获取是由构造函数实现,而资源释放是由析构函数完成”。采用面向对象的程序设计,取得资源的动作封装在类的构造函数中,释放资源的动作封装在类的析构函数中,当一个函数带着未处理的异常退出时,函数中这种类对象被自动销毁,资源(包括动态空间分配的资源和打开的文件)释放。所以由文件重构对象应该放在构造函数中
15、,把对象存入文件应该放在析构函数中。,栈展开时资源的释放:,异常处理应该用于面向对象的程序设计。对非面向对象的程序设计如果函数动态获得过资源,因异常,这些资源的释放语句可能被忽略,则这些资源将永远不会被自动释放。,10.3 栈展开与异常捕获,异常不能够保持在未被处理的状态。异常表示一个程序不能够继续正常执行,这是非常严重的问题,如果没有找到处理代码,程序就调用C+标准库中定义的函数terminate()。,异常对象的探讨:异常对象是在throw表达式中建立并抛出:throw表达式通过调用异常类的构造函数创建一个临时对象,然后把这个临时对象复制到一个被称为异常对象(exception objec
16、t)的存贮区中,它保证会持续到异常被处理完。,10.3 栈展开与异常捕获,函数调用和异常处理的区别:建立函数调用所需要的全部信息在编译时已经获得,而异常处理机制要求运行时的支持。对于普通函数调用,通过函数重载解析过程,编译器知道在调用点上哪个函数会真正被调用。但对于异常处理,编译器不知道特定的throw表达式的catch子句在哪个函数中,以及在处理异常之后执行权被转移到哪儿。这些都在运行时刻决定,异常是随机发生的,异常处理的catch子句是逆调用链进行查找,这与运行时的多态虚函数也是不一样的。当一个异常不存在处理代码时,系统无法通知用户,所以要有terminate()函数,它是一种运行机制,当



- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- C+ 电子 课件 第十

链接地址:https://www.31ppt.com/p-6153973.html