




下载本文档
版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
第十 异常处大型和十分复杂的程序往往会产生一些很难查找的甚至是大型和十分复杂的程序往往会产生一些很难查找的甚至是无法避免的运行时错误。当发生运行时错误时,不能简单地结束程序运行,而是退回到任务的起点,错误,并由用户决定下一步工作。面向对象的异常处理(ecepionhandling)机制是语言用以解决这个问题的有力工具。函数执行时,放(测试)程序块中的任何类型的数据对象发生异常,都可被thrw块抛出,随即沿调用链退回,直到被cach块捕获,并在此执行异常处理,报告出现的异常等情况。从抛出到捕获,应将各嵌套调用函数残存在栈中的自动对象、自动量现保内等行除如果退到 函数还未捕获则由bort(来终结 函数。第十 异常处10.1异常的10.1异常的概 异常处理的机10.5异常规10.3栈展开常捕 异常和继10.410.4异常的重新抛和catch_all子 C++标准库异常层次结异常的概这里所讲的异常(exception)是 是无法确知怎样发生和何时发生。特别在一个大型的程序(软件)C++提供了一些内置的语言特性来产生(raise) 异常处理的首先,在C++中异常往往用类(class)为例,异常 如下classpopOnEmpty//栈空异常classpushOnFull{...};//栈满异常测到栈满或空就抛出一个异常template<typenameT>voidif(IsFull())throwelements[++top]=data;}template<typenameT>TStack<T>::Pop(){if(IsEmpty())throwpopOnEmpty<T>();returnelements[top--];}注意puhOnFul是类,C++要求抛出的必须是对象,所以必须有“”,即调用构造函数建立一个对象。异常处理的异常并非总是类对象,thow表达式也可以抛出任何类型的对象,如枚举、整数等等。但最常用的是类对象。thow表达式抛出异常为异常处理的第一步。在堆栈的压在中建立异常抛出与异常处理之间有一整套程序设计的机制。首先采用关键字tr,构成一个tr块(tryblock),它包含了抛出异常异常处理的机请看下面的程序段给出try块与catch子句的关系intinttry{for(i=0;i<9;i++)istack.PrintStack();}try{for(i=0;i<9;i++){b[i]=istack.Pop();}}for(i=0;i<9;i++)cout<<b[i]<<’\t’;return0;异常处理的机这里有两个tr块,分别对应压栈与出栈;也有两个catch子句(catchclause),分别处理压栈时的栈满和出栈时的栈空。由catch字句捕获并处理异常是第二步。注意与ctch语句分别匹配thrw一个抛出pushOnFul类的无名对象,另一个抛出ppOnEmp类的无名对象。在编制程序时有一条惯例:把正常执行的程序与异常处理两。在上例中,我们可以把两个tr块合成一个,而把两个ctch子句都放在函数最后。异常处理的机程序按下列规则控制如果没有异常发生,继续执行ty块中的代码,与ty块相关联的catch子句被忽略,程序正常执行,ain返回0。当第一个try块在for循环中抛出异常,则该for循环退出,try块也退出,去执行pushOnFull异常的catch子句。如果第二个try块调用Pop()抛出异常,则退出for和块,去执行popOnEmpty异常的catch子句当某条语句抛出异常时,跟在该语句后面的语句将被跳过。程序执行权交给处理异常的cach子句,如果没有atch子句能够处理异常,则交给C+标准库中定义的tinat。异常处理的机把程序的正常处理代码和异常处理代码分离的最清楚的方法是定义函数tr块(fnctiontryblock)但V6.0不支持。intmain()intstack return0;catch(popOnEmpty<int>){cerr<<”栈空”<<endl;returncatch(pushOnFull<int>){cerr<<”栈满”<<endl;return栈展开与异常捕catch子句由三部分组成:关键字catch、圆括号中的异常 以及复合语句中的一组语句。catchcatch子句不是函数,所以圆括号中不是形参,而是一异常类 ,可以是类型也可以是对象catch子句的使用:它只有一个子句,没有定义和调用分。使用时由系统按规则自动在catch子句列表中匹配catch子句可以包含返回语句(tun),也可不包含返回语句。包含返回语句,则整个程序结束含返回语句,则执行ath列表之后的下一条语句。异 中也可以是一个对 。以栈为例当栈满时,要求在异常对象中保存不能被压入到栈中的值,这时,pshnul类可定义如下:template<typenameT>classpushOnFull{T_value;pushOnFull(T //或写为pushOnFull(Ti){_value=i;}Tvalue(){return_value;}};新的私有数据成员_value保存值即调用构造函数时的实参对应在throw表达式中throw//data即Push(const&data)中的参数*catch子句异中采用对象只是一种形式。甚*catch子句异中采用对象只是一种形式。甚异常并非一个类对象时,也可以用同样的格式,比异常为一枚举量用类对象的公有成员在catch子句中,要取得_alu,须调用pushOnFull中的成员函数value:catch(pushOnFull<T>cerr<<”栈满”<<eObj.value()<<”未压入return在catch子句的异常 中 了对象Ob,用它来调用pushOnFu类的对象成员函数valu。异常对象是在抛出点被创建,与ctc子句是否显式要求创建一个异常对象无关,该对象总是存在,在at子句中只是为了调用异常处理对象的成员函数才 为对象,不用类。栈展开与异常捕catch子句的异常与函数参数类似,可以值传送,也可以是按传递。对大型类对象减少不必要的拷贝是很有意义的,所以对于类类型的异常,其异常最好也是被为。如:catch(pushOnFull<T>&return1;}使用 类型的异常 cach子句能够修改异常对象,但仅仅是异常对象本身,正常程序部分的量并不会被修改与一般类对象不同,实际上异常对象处理完后,生命期也就结束了。只有需要重新抛出异常(在下一节中讨论),修改操作才有意义。try块相关联的catch子句列表则处理该异常;没有,则查找过程在该函数的主调函数中继续进行。即这个查找过一个匹配的catch子句,就进入该catch子句,进行处理查找过程结束栈展开与异常捕展开(stackunwinding)。这是异常处理的 在栈异常处理的例子中,对ppOn,首先应在istack的成员函数Pop中找,因为Pop中的tw表达式没有在块中,所以Pop带着一个异常退出。下一步是检查调用Pop的函数,这里是ain(,在ain(中对op的调用位于一个块中,则可用与该块关联的cach子句列表中的某一个来处理,找到第一个popnEmp类型异常声明的cach子句,并进入该子句进行异常处理。而且可能逆调用链而上,甚至整个任务。因此,异常处理应该在其对程序影响的终结处进行,甚至是在调用该任务的菜单处进行。栈展开与异常捕退出调用链时必须释放所有资源,由系统回收在栈展开期间,在退出的域中有某个局部量是类对象,栈展异常处理过程本质上反映的是“资源获取是由构造函数实现,而资源释放是由析构函数完成”。采用面向对象的程序设计,取得资源的动作封装在类的构造函数中,释放资源的动作封装在类的析构函数中,当一个函数带着未处理的异常退出时,函数中这种类对象被自动销毁,资源(包括动态空间分配的资源和打开的文件释放。所以由文件重构对象应该放在构造函数中,把对象存入文件应该放在析构函数中。异常处理应该用于面向对象的程序设计。对非面向对象的程序设计如果函数动态获得过资源,因异常,这些资源的释放语句可能被忽略,则这些资源将不会被自动释放。栈展开与异常捕异常对象是在tw表达式中建立并抛出:tw表然后把这个临时对象拷贝到一个被称为异常对象(exceptionobject)的存贮区中,它保证会持续异常被处理完 栈展开与异常捕函数调用和异常处理的主要区别是建立函数调用所需要的全部信息在编译时已经获得,而异常处理机制要求运行时的支持。对于普通函数调用,通过函数重载解析过程,编译器知道在调用点上哪个函数会真正被调用。但对于异常处理,编译器不知道特定的tw表达式的catch子句在哪个函数中,以及在处理异常之后执行权被转移到哪儿。这些都在运行时刻决定,异常是随机发生的,异常处理的catch子句是沿调用链逆向进行查找,这与运行时的多态编译器无法通知用户,所以要有eae函数,它是一种运行机制,当没有处理代码(ctch子句)能够匹配,被抛出的异常时由它通知用户。异常的重新抛出和catch_all子当catch语句捕获一个异常后,可能不能完全处理完成某些操作后,该异常必须由函数链中更的函数来处理,这时ach子句可以重新抛出(ethr)该异常,把异常传递给函数调用链中更的另一个cach子句,由它进行进一步处理。但仅有一个关键字,因为异常类型在catch语句中已经有了,不必再指明。被新出异就原的常象。但是重新抛出异常的cach子句应该把自己做过的工作告诉下一个处理异常的catch子句,往往要对异常对象做一定修改,以表达某些信息,因此ath子句中的异常 必须被 为 ,这样修改才能真正做在异常对象自身中,而不是拷贝中。异常的重新抛出和catch_all子通用形式的catch子句catch(...){代码任何异常都可以进入这个catch为省略号。花括号中的复合语句用来执行指定操作异常发生后按栈展开(stackunwinding)退出,动态分配的非voidfun1(){int*res;res=newint[100//定义一个资源对try{//代码包括使用资源res和某些可能引起异常抛出的操 //异常可能有多catch(...){//不论是那种异常都在此释放delete[]res;//释放资源对象resthrow;}//重新抛出异常deleteres;//正常退出前释放资源对象异常的重新抛出和catch_all子cac_all子句可以单独使用,也可以与其它cach子句联合使用。如果联合使用,它必须放在相关子句表的最后。catch子句被检查的顺序与它们在try块之后排列顺序相同,一旦找到了一个匹配,则后续的ach子句将不再检查,按此规则,catch_all子句(cach(...){})处理表前面所列各种异常之外的异常。如果只用catch_all子句进行某项操作,则其他的操作应由catch子句重新抛出异常,沿调用链逆向去查找新的处理子句来处理,不能在子句列表中再按排一个处理同一异常的子句,因为第二个子句是 执行不到的。异常规范(exceptionspecification)提供函数(函数指针 列出该函数可能抛出的异常
案不会抛出任何其他类型的异常,在stack类定义中可有viodPush(constT&data)throw(pushOnFull,Over,int,double)TPop()throw(popOnEmpty);成员函数类内 和类外定义必须必须在两处都有相同的异常规同样的异常规范。一个函数的异常规范的违例只能在运行时才能被检测出来。如果在运行时,函数抛出了一个没有被列在它的异常规范中的异常时(并且函数中所抛出的异常,没有在该函数 理)则系统调用标准库中定义的函unexpcted(。如果异常规范为tw(,则表示不得抛出任何异常。必 VC++6.0不支持异常规学习了前几节内容后,给出下例作为小【例10.1】包含栈满或空异常在C++程序中,表示异常的类通常被组成为一个(即 面各节讨论的那样)或者一个层次结构classExcp{public:voidprint(stringmsg){cerr<<msg<<endl;}};再从该基类派生出两个异常类classstackExcp:publicExcp{...};//栈异常类的基类classmathExcp:publicExcp{..//数学库异常的基类classpopOnEmpty:publicstackExcp{...};//栈空退栈异常classpushOnFull:publicstackExcp{...};//栈满压栈异常classzeroOp:publicmathExcp{...};//数学 classdivideByZero:publicmathExcp{...};//数学库被零除异常形成了三层结构 在层次结构下,异常的抛出会有一些不同,以下做法是错的pushOnFullstackExcp*pse=&except//pse指向的类对象为pushOnFullthrow*pse;}//抛出的异常对象的类型为stackExcp这里被创建的异常类对象sackxcp类类型,尽管pe指向一个实际类型pushnFul的对象,但那是一个临时对象,拷贝到异常对象的 区中时创建的却sackxcp类的异常对象。所以该异常不能被puhOnFul类型的cach子句处理。 catch(pushOnFull){...}//处理pushOnFull异常catch(stackExcp){...}//处理栈的其他异常catch(Excp//处理一般异catch(…)派生类类型的catch子句必须先出现,以确保只有在没有其catch子句适用时,才会进入基类类型的catch异常catch子句不必是与异常最匹配的atch子句,而是最先匹配到的catch子句,就是第一个遇到的可以处理该异常的catch子句。所以在atch子句列表中最特化的(匹配条件最严格的)cach子句必须先出现。虚函数是类层次结构中多态性的基 ,异类层次结构中也可以定义虚拟函数 类层次结构的异常同样可以重新抛出(rethrow),把一个常传递给函数调用列表中更上层的另一个catchpushOnFull类类型的异常,而它被基类的ctch子句处理,并在其中再次被抛出,那么这个异常仍是phOnul类类型的异常,而不是其基类类型的异常。在基catch子句处理的是异常对象的基类子对象的一份拷贝该拷贝只在该catc子句中被 ,重新抛出的是原来的异常对象。这个放在异常对象 区中的异常的生命期应该是在处理该异常的一系列的子句中最后一个退出时才结束,也是直到这时,才由异常类的析构函数来销毁它。这一系列的子句是由重新抛出联系起来的。【例10.2】异常层次结构中的虚函数。为了调用派生类对的虚拟函数,异常 必须为一个指针或虚函数中异常规范可以不同。派生类的虚拟必须与基类虚函数的异常一样或更严格(是基类虚函数的异常的子集)。因为当派生类的虚函数被指向基类类型的指针调用时,保证不会违背基类成员函数的异常规范。classCBase{virtualintfun1(int)throw();virtualintfun2(int)throw(int);virtualstringfun3() classCDerived:publicCBase{intfun1(int)//错!异常规范不如throw()严intfun2(int)throw(int);//对!有相同的异stringfun3()throw(string);//对!异常规范throw(int,string)更严C++标准库中的异常层次的根类被称为定义在库的头文件<exception>exception类的接口如下namespacestd//注意在名字空间域stdclassexception()throw//缺省构造函exception(constexception&)throw()//拷贝构造函exception&operator=(constexception&)throw()//拷贝赋值操作virtual~exception()throw();//析构函数virtualconstchar*what() throw()//返回一个C} C++标准库提供的逻辑异常包括inalid_aent异常,接收到一个无效的实参,抛出该异常。ou_o_ange异常,收到一个不在预期范围中的实参,则抛出。lenh_er异常,报告企图产生“长度值超出最大允许值”的对象 以上三个异常是由runtime_error类派生的异常。当ew()操作符不能分配所要求 区时,会出该异常。它是由基类exception派生的【例10.3】为类模板Array重新定义operator[](),如索引值越界,它会抛出一个out_of_range类型的异常第十 异常处完谢谢[例10.1]堆栈异常处template<typenameT>classpushOnFull{//栈满异常T_value;pushOnFull(Ti){_value=i;}Tvalue(){return_value;}template<typenameT>classpopOnEmpty{//栈空异voidprint(){cerr<<"栈已空,无法出栈[例10.1]堆栈异常处template<typenameT>classinttop; T //动态建立的数int //栈最大允纳 //栈如不指定大小,设为20元~Stack(){delete[]voidPush(constT&data)throw(pushOnFull<T//压TPop()throw(popOnEmpty); TGe em(inti){returnelements[i];}//返回指定元素voidMakeEmpty(){top=-1;} boolIsEmpty()const{returntop==-1;} boolIsFull()const{returntop==maxSize-1;} voidPrintStack(); [例10.1]堆栈异常处template<typenameT>voidStack<T>::Push(constTif(IsFull())throwpushOnFull<T>(data);//栈满则抛出异//栈顶指针先加1,元素再进栈,top是指向栈顶元}template<typenameT>TStack<T>::Pop()if(IsEmpty())throw//栈已空则不能退栈,抛出异returnelements[top--];//返回栈顶元素,同时栈顶指针退}[例10.1]堆栈异常处intinta[9]={1,2,3,4,5,6,7,8,9},for(i=0;i<9;i++)istack.Push(a[i]//到a[8]时栈满,异}try{for(i=0;i<9;i++)b[i]=istack.Pop();}catch(popOnEmpty<int>&eObj){eObj.print();}for(i=0;i<9;i++)cout<<b[i]<<'\t';return0;}[例10.2]异常层次结构中的虚函class virtualvoidprint(){cerr<<"发生异常classstackExcp:public virtualvoidprint(){cerr<<"栈发生异常classpushOnFull:public virtualvoidprint(){cerr<<"栈满,不能压栈classpopOnEmpty:public void
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 2025年健身服项目市场调查研究报告
- 智能温控户外服装品牌行业跨境出海战略研究报告
- 智能温控炖汤机行业深度调研及发展战略咨询报告
- 智能监控企业制定与实施新质生产力战略研究报告
- 烘炒多用途冷却设备行业跨境出海战略研究报告
- 智能手套手势控制企业制定与实施新质生产力战略研究报告
- 智能机场照明行业跨境出海战略研究报告
- 智能睡眠监测行业深度调研及发展战略咨询报告
- 物料配送绿色包装方案行业深度调研及发展战略咨询报告
- 儿童家具购买合同范例
- DB50∕T 995-2020 新增耕地质量评定技术规范
- 心血管内科专病数据库建设及研究
- 康复科并发症二次残疾
- 《工业机器人工作站应用实训》项目三工业机器人涂胶工作站的应用实训课件
- 土石坝(枢纽溢洪道)毕业设计
- (新版)拖拉机驾驶证科目一知识考试题库500题(含答案)
- 2025年中考物理一轮复习:物理学与社会发展 专项练习
- DL∕T 526-2013 备用电源自动投入装置技术条件
- 2024年北京大兴区九年级初三一模英语试题和答案
- JT-T-848-2013公路用复合隔离栅立柱
- 食品生物化学 知到智慧树网课答案
评论
0/150
提交评论