C++程序设计课件(第5章)

上传人:仙*** 文档编号:245300794 上传时间:2024-10-08 格式:PPT 页数:57 大小:181.50KB
返回 下载 相关 举报
C++程序设计课件(第5章)_第1页
第1页 / 共57页
C++程序设计课件(第5章)_第2页
第2页 / 共57页
C++程序设计课件(第5章)_第3页
第3页 / 共57页
点击查看更多>>
资源描述
,单击此处编辑母版标题样式,单击此处编辑母版文本样式,第二级,第三级,*,*,C/C+程序设计教程-面向对象分册,第,5,章 异常处理,本章学习重点掌握内容:,异常的概念、异常的产生,异常的处理机制,throw,、,try,和,catch,的用法,捕捉所有的异常,异常信号的传递方式,标准,C+,库的异常类,10/8/2024,1,第,5,章 异常处理,5.1,异常的概念,5.2,异常处理机制,5.3,没有被捕捉的异常,5.4,catch,(,.,)使用,5.5,用类的对象传递异常,5.6,标准,C+,库中的异常类,5.7,综合应用实例,10/8/2024,2,5.1,异常的概念,5.1.1,异常的概念,程序运行过程中,由于环境变化、用户操作失误以及其它方面的原因而产生的运行时不正常的情况,它要求程序立即进行处理,否则将会引起程序错误甚至崩溃的现象。,常见的异常有:空闲内存耗尽、请求打开不存在的文件、被,0,除、打印机未打开、数组越界访问等。,10/8/2024,3,5.1.2,异常的产生,C+,程序是由一些相互分离的模块组成的,程序中出现错误和解决出现的错误就会分成两个部分,:,(,1,)某个模块,A,出现错误,但它并没有能力在模块,A,内解决这个错误,因此它就给出关于这个错误的报告。,(,2,)某个模块,B,能够检测到模块,A,发出的错误报告,并处理这个错误,使出现错误造成的损失减到最小。,10/8/2024,4,5.2,异常处理机制,5.2.1,基本概念,1,抛出异常,如果程序发生异常情况,而在当前的上下文环境中获取不到处理这个异常的足够信息,程序将创建一个包含出错信息的对象并将该对象抛出当前上下文环境,将错误信息发送到更大的上下文环境中,这个过程称为抛出(,throw,)异常。,10/8/2024,5,5.2.1,基本概念,2,捕捉异常,对于一个抛出的异常,如果某一个模块能够(或想要)处理这个异常,它就可以获得程序的控制权处理该异常,这个过程称为捕捉(,catch,)异常。,3,处理异常,当某个,catch,块捕捉到异常后,它就根据事先制定的策略对异常进行处理,这就是处理异常。在,C+,中,只有,catch,块能够捕获异常并进行处理,因此,catch,块又称为异常处理器。,10/8/2024,6,5.2.1,基本概念,4,C+,的异常处理机制,C+,的异常处理机制就是将抛出异常与捕捉异常、处理异常分离开来。抛出异常的模块并不负责异常的处理,它只是报告某个地方存在错误,这个报告可以帮助异常处理器解决这个错误。而异常处理器则根据抛出异常模块的报告来处理异常,如果没有模块抛出异常,就不会有异常的处理。,10/8/2024,7,5.2.2 throw,语句,抛出异常的语法格式如下:,throw,表达式,这里,,throw,后的表达式表示异常的类型,它可以是一个变量或一个对象。,throw,语句在语法上与,return,语句相似。下面是两条,throw,语句的例子。,throw 1;,throw ( “,出现异常”,);,异常抛出后,程序的控制权就从异常抛出的地方交出,由编译器寻找匹配的异常处理器进行相应的处理。,10/8/2024,8,5.2.3,try,块,try,块的语法格式如下:,try,复合语句,try,块必须包围能够抛出异常的语句。它提示编译器到那里查找异常处理器,没有跟在,try,块后的,catch,块是没有用的。,try,块可以包含任何,C+,语句,甚至包含整个函数。,10/8/2024,9,5.2.4 catch,块,catch,块的语法格式如下。,catch(,异常类型声明,),异常处理语句,catch(,异常类型声明,),异常处理语句,10/8/2024,10,5.2.4 catch,块,catch,后括号中的异常类型声明可以是一个类型或一个对象声明,后边一对“,”,括住的是一组复合语句。一个,catch,块相当于一个以类型为单一参数的函数。,catch,块必须直接放在,try,块之后。,catch,语句与,switch,语句不同,它不需要在每个,case,语句后加入,break,用以中断后面程序的执行。,一个,catch,块引入一个局部域,在,catch,块内声明的变量不能在,catch,块外引用。,10/8/2024,11,【,例,5.2】,局部域声明的变量不能被局部域外引用例题。,#include ,void main(),try, /,一段可能引起异常的代码,throw (,出现异常!,);,catch (char* message),int,y = 1;,cout,处理了,char*,类型的异常,endl,;,cout,y,endl,; /,编译错误,变量,y,未定义,10/8/2024,12,5.2.5,异常处理模式,C+,的异常处理有两种基本模式:,1,终止模式,异常抛出后,捕捉异常并退出导致异常的子程序或子系统,退出需要关闭适当的文件,析构适当的对象,释放适当的内存,处理需要处理的设备等,这种方法称为终止模式。,缺省情况下,,C+,异常处理机制采用终止方法。,【,例,5.3】,捕捉异常后直接退出的例题。,10/8/2024,13,#include ,void func2(),/,一段有可能引起异常的代码,throw 1;,cout,其它程序语句!,endl,;,void main(),try,10/8/2024,14,func2 (); / func2 (),抛出的异常值为,1,/,程序抛出异常后的语句部分,cout,异常处理结束后继续执行!,endl,;,catch (,int,x),/,对异常的处理,cout,处理了,int,类型的异常,endl,;,cout,程序结束!,endl,;,在采用终止模式情况下程序的运行结果为:,处理了,int,类型的异常!,程序结束!,10/8/2024,15,5.2.5,异常处理模式,2,恢复模式,异常抛出后,捕捉异常并试图去纠正或调整引起异常的条件,然后从发生异常的地方继续执行,这种方法称为恢复模式。,恢复模式实现起来非常困难,在实际应用中,除了一些特殊的领域外,一般都不采用恢复模式处理异常。,10/8/2024,16,5.2.6,重新抛出,在异常处理过程中也可能存在“单个,catch,子句不能完全处理这个异常”的情况。那么该异常处理器在做完局部能够做的事情后,会再一次抛出这个异常,让函数调用链中更上级的函数来处理,这个过程称作重新抛出(,rethrow,),重新抛出的语法形式如下:,throw;,重新抛出的还是原来捕捉到的那个异常。重新抛出只能出现在,catch,块中。,10/8/2024,17,【,例,5.4】,重新抛出捕捉的异常例题。,#include ,void func3(int x),try, /,一段有可能引起异常的代码,throw x;,catch (,int,x),/,如果异常参数,x=0,则进行处理,否则继续抛出,if(x,=0), /,对异常的处理,else,cout,重新抛出异常!,endl,;,10/8/2024,18,throw; /,重新抛出,void main(),try, func3 (1); /,程序其它部分,catch (,int,x),/,对异常的处理,cout,处理了,int,类型的异常!,endl,;,10/8/2024,19,程序运行结果为:,重新抛出异常!,处理了,int,类型的异常!,有的情况下,异常处理器在重新抛出之前会对异常信号进行一些修改,这个修改能够影响更高级函数调用链中的异常处理器对该异常的处理。,5.2.6,重新抛出,10/8/2024,20,5.2.7,异常规范,异常规范规定:随着函数声明列出该函数可能抛出的异常,并保证该函数不会抛出其它类型的异常。常见附带异常说明的函数说明有以下,3,种情况。,(,1,)函数返回类型 函数名,(,参数列表,)throw(,类型列表,),;,(,2,)函数返回类型 函数名,(,参数列表,) throw(),;,(,3,)函数返回类型 函数名,(,参数列表,),;,第一种情况,函数列出所有可能抛出的异常类型;第二种情况表示函数不会抛出任何类型的异常;第三种情况表示函数可能抛出任何类型的异常。,异常规范并非强制规定,因此,没有在函数说明后附带异常说明并非语法错误。,10/8/2024,21,【,例,5.6】,异常规范的处理例题,void func5(int x),throw(int, char*),/x,等于,0,抛出,int,型异常,,x,小于,0,抛出,char*,型异常,,x,大于,0,/,什么也不做,if(x,=0),throw 0;,if(x,0),throw error;,void func6() throw(), /,本函数完成,10,个指令周期的延时,不抛出任何异常,int,i = 0;,while(i,10),i+;,10/8/2024,22,5.2.7,异常规范,有时,函数可能抛出没有列入异常规范的异常,出现这种情况时,系统分两种情况进行处理。,(,1,)在函数内部(包括抛出异常的函数以及调用该函数的函数链中的任意函数)捕捉到了这个异常,进行了处理,则程序可以继续执行。,(,2,)异常被抛到函数外部,系统会调用,C+,标准库中定义的函数,unexpected(),,该函数的缺省行为是调用,terminate(),,终止程序的运行。当然,在,C+,中,可以改变,unexpected(),的缺省行为。,10/8/2024,23,5.3,没有被捕捉的异常,根据异常匹配的规则,如果,try,块后面的所有的,catch,块都没有与某一异常相匹配,这时内层对异常的捕获失败,异常将进入更高层的上下文环境中进行匹配,这个过程一直进行直到在某个层次异常处理器与该异常相匹配,这时才认为捕获了这个异常。,10/8/2024,24,5.3,没有被捕捉的异常,如果任意层的异常处理器都没有捕获到这个异常,那么这个异常最终会抛给,main(),函数,如果在,main(),中还没有找到合适的匹配,则称这个异常是“未捕捉的”或“未处理的”。如果一个异常未被捕捉,就会调用函数,terminate(),,终止本程序的运行。,10/8/2024,25,【,例,5.7】,未被捕捉的异常处理例题,#include ,void func7(),throw 0;,void main(),try func7(); ,catch (double d),cout,进行了异常处理!,endl,; ,10/8/2024,26,例子,5.7,中,,func7(),函数中抛出了,int,型的异常,最后抛给了,main(),函数,在,main(),函数中也没找到合适的匹配,于是终止本程序运行,,main(),函数,catch,块后边的程序其它部分不再执行。,如果在所有函数之外的代码出现异常,比如全局对象的构造和析构等,如果有相应的异常处理器捕捉到抛出的异常,则异常处理后继续,main(),函数的执行,如果没有捕捉到抛出的异常,则终止本程序运行。,5.3,没有被捕捉的异常,10/8/2024,27,5.4 catch,(,.,)使用,C+,在异常处理中提供了一个能捕捉所有异常的,catch,块。,catch,块的语法格式如下:,catch(),异常处理语句,其中,列表中的“,”,表示可捕获所有的异常,但使用省略号就不可能有参数,也不可能知道所接受到的异常为何种类型。其它部分和普通,catch,块完全一样。,10/8/2024,28,【,例,5.9】,使用,catch(.),语句的异常处理例题,#include ,void func5(int x),throw(int,),/x,等于,0,抛出,int,型异常,,x,小于,0,抛出,char*,型异常,if(x,=0) throw 0;,if(x,0) throw error;,void main(),try,int,x = 0;,cout,x;,10/8/2024,29,func5(x);,/,程序其它部分,catch(.),/,对异常的处理,cout,处理了所有类型的异常!,endl,;,cout,程序结束!,endl,;,程序运行结果如下:,请输入一个,int,类型数据:,0,处理了所有类型的异常!,10/8/2024,30,5.5,用类的对象传递异常,异常信息传递是指将,throw,语句抛出的异常参数传递到,catch,块中。但在实际应用中,由于抛出异常信息的需要,经常使用类的对象传递异常。使用对象传递异常还有以下,2,个好处:,(,1,)在,C+,中,很好地实现了,RTTI,(,Run-Time Type Information,)技术,使用对象传递异常,可以很好地完成异常对象的类型匹配。,(,2,)在,C+,中,很好地实现了对象的构造、销毁、转存复制等技术,可以很好的实现异常信息的传递、修改和销毁等。,同函数参数传递方式一样,异常参数的传递有,3,种方式:传值方式、引用方式和指针方式,10/8/2024,31,5.5.1,传值方式传递异常对象,按传值方式传递异常对象时,被抛出的异常都是局部变量,而且是临时的局部变量。也就是说,每当在,throw,语句抛出一个异常对象时,不管构造的对象是什么性质的变量,此时它都会复制一份临时局部变量。,【,例,5.10】,按传值方式传递异常对象例题。,#include,#include,using namespace std;,10/8/2024,32,class,CMyException,/,异常类,该类的对象作为抛出异常时传递的异常参数。,public:,CMyException,(string n=none) :,name(n,),/,根据参数,n,构造一个名字为,n,的异常类对象,cout,“,构造一个,CMyException,对象,名称,为:,name,endl,;,CMyException,(const,CMyException,& e),/,根据参数,e,拷贝构造一个异常类对象,name =,e.name,;,cout,“,拷贝一个,CMyException,对象,名称,为:,name,endl,;,10/8/2024,33,virtual ,CMyException,(),cout, “,销毁一个,CMyException,对象,名称,为:, name,endl,;,string,GetName,() return name;,protected:,string name; /,异常类对象的名字,;,void main(),try /,构造一个异常对象,这是个局部变量。,CMyException,obj1(obj1);,10/8/2024,34,/,下面抛出异常对象。注意:这时,VC,编译器会复制,/,一份新的异常对象,即调用一次,CMyException,/,类的拷贝构造函数。新拷贝的对象是个临时变量。,throw obj1;,catch(CMyException,e), /,当异常参数传递给,e,时,由于是传值方式,因,/,此会调用一次拷贝构造函数,cout,“,捕获一个,CMyException,类型异常,,名称为:,e.GetName,(),endl,;,cout,程序运行结束!,endl,;,10/8/2024,35,5.5.1,传值方式传递异常对象,程序运行的结果为:,构造一个,CMyException,对象,名称为:,obj1,拷贝一个,CMyException,对象,名称为:,obj1,拷贝一个,CMyException,对象,名称为:,obj1,销毁一个,CMyException,对象,名称为:,obj1,捕获到一个,CMyException,类型的异常,名称为:,obj1,销毁一个,CMyException,对象,名称为:,obj1,销毁一个,CMyException,对象,名称为:,obj1,程序运行结束!,10/8/2024,36,5.5.1,传值方式传递异常对象,例,5.10,中,调用了,1,次,CMyException,类的构造函数,,2,次,CMyException,类的拷贝构造函数。,在,main(),的,try,块中,定义对象,obj1,时,调用,1,次,CMyException,类的构造函数。,通过,throw,语句抛出异常对象,obj1,时,复制了一份,obj1,的临时局部变量,调用,1,次,CMyException,类的拷贝构造函数,找到匹配的,catch,块后,由于是按值传递异常参数,又调用一次,CMyException,类的拷贝构造函数。,10/8/2024,37,5.5.1,传值方式传递异常对象,例,5.10,中,调用了,3,次,CMyException,类的析构函数。,在进入,catch,块之后,进行异常处理之前,调用了一次,CMyException,类的析构函数,这时析构的是,try,块中定义的局部变量,obj1,。,在离开,catch,块时,又调用了两次,CMyException,类的析构函数,先析构的是进入,catch,块是构造的异常参数,obj1,,然后再析构,throw,语句创建的临时局部变量,obj1,。,10/8/2024,38,5.5.2,引用方式传递异常对象,按引用方式传递异常对象时,被抛出的异常也是临时局部变量。,【,例,5.11】,按引用方式传递异常对象的例题。,#include,#include,using namespace std;,/,插入例,5.10,中,CMyException,类的定义,void main(),try,/,构造一个异常对象,这是个局部变量。,CMyException,obj1(obj1);,10/8/2024,39,/,这里抛出异常对象。注意:这时,VC,编译器会复制,/,一份新的异常对象,即调用一次,CMyException,/,类的拷贝构造函数。新拷贝的对象是个临时变量。,throw obj1;,catch(CMyException,&e) /,按引用方式传值, /,此处传递给,e,的实际是上面临时对象的引用,,/,因此不调用任何构造函数。,cout,“,捕获一个,CMyException,类型异常,,名称为:,e.GetName,(),endl,;,cout,程序运行结束!,endl,;,10/8/2024,40,5.5.2,引用方式传递异常对象,程序运行的结果为:,构造一个,CMyException,异常对象,名称为:,obj1,拷贝一个,CMyException,异常对象,名称为:,obj1,销毁一个,CMyException,异常对象,名称为:,obj1,捕获到一个,CMyException,类型的异常,名称为:,obj1,销毁一个,CMyException,异常对象,名称为:,obj1,10/8/2024,41,5.5.2,引用方式传递异常对象,例,5.11,中,调用了,2,次,CMyException,类的构造函数。,在,main(),的,try,块中,定义对象,obj1,时,调用,1,次,CMyException,类的构造函数。,通过,throw,语句抛出异常对象,obj1,时,复制了一份,obj1,的临时局部变量,调用,1,次,CMyException,类的拷贝构造函数,由于,catch,块是按引用方式传递异常对象,传递给,catch,块的是临时异常对象的引用,因而不需要调用异常类的构造函数。,10/8/2024,42,5.5.2,引用方式传递异常对象,在例,5.11,中,调用了,2,次,CMyException,类的析构函数。,在进入,catch,块之后,进行异常处理之前,调用了一次,CMyException,类的析构函数,这时析构的是,try,块中定义的局部变量,obj1,。,在退出,catch,块时,又调用了一次,CMyException,类的析构函数,这时析构的是调用,throw,语句时构建的临时异常对象。,10/8/2024,43,5.5.3,指针方式传递异常对象,与传值方式和引用方式传递异常对象相比,在按指针方式传递异常时,异常对象的构造方式有很大的不同。它要么是在堆中动态构造的异常对象,要么是静态全局对象,而不能是局部变量。,【,例,5.12】,按引用方式传递异常的例题。,#include,#include,using namespace std;,/,插入例,5.10,中,CMyException,类的定义,void main(),10/8/2024,44,try/,动态在堆中构造的异常对象,调用一次构造函数。,throw new,CMyException,(obj1);,/,注意:这里是定义了按指针方式传递异常对象,catch(CMyException,* e), /,此处传递给,e,的实际是上面动态对象的地址,,/,因此不调用任何构造函数。,cout,“,捕获到一个,CMyException,*,类型的异,常,名称为:,GetName,(),endl,;,delete e; /,动态创建的对象需要销毁,程序运行的结果为:,构造一个,CMyException,异常对象,名称为:,obj1,捕获到一个,CMyException,*,类型的异常,名称为:,obj1,销毁一个,CMyException,异常对象,名称为:,obj1,10/8/2024,45,5.5.3,指针方式传递异常对象,例,5.12,中,只在异常抛出时调用了一次,CMyException,类的构造函数。,动态地创建对象,也要动态的销毁,因此,在退出,catch,块之前调用,delete,语句销毁异常对象时调用了一次,CMyException,类的析构函数。,10/8/2024,46,5.5.4,异常对象传递方式的比较,传递方式,传值方式,引用方式,指针方式,抛出对象,局部临时对象,局部临时对象,堆对象,全局静态对象,catch,语句,catch(,类型,e),catch(,类型,&e),catch(,类型 *,e),构造对象,次数,3,2,1,运行效率,低,中,高,10/8/2024,47,5.5.4,异常对象传递方式的比较,传递方式,传值方式,引用方式,指针方式,异常对,象销毁,局部变量离开作用域,时销毁;临时变量,catch,块执行完后销毁;,异常类型参数在,catch,块执行完后销毁。,局部变量离开,作用域时销毁;,临时变量在,catch,块执行完后,销毁。,在,catch,块最,后显式调用,delete,语句,销毁。,安全性,中,高,低,依赖程,序员的能力,综合性能,差,好,中,易使用性,好,好,一般,10/8/2024,48,5.6,标准,C+,库中的异常类,在标准,C+,库中提供了一个异常类的基类,exception,和它的多个派生类。分别介绍如下。,1. ,头文件中定义了异常类,exception,和,bad_exception,,异常类,exception,是标准,C+,库中所有异常类的基类。,2. ,头文件中定义了异常类,ios_base:failure,。,3. ,头文件中定义了异常类,bad_cast,和,bad_typeid,,当,dynamic_cast,失败时将抛出该异常类对象。,4. ,头文件中定义了其它所有的异常类,如,logic_error,、,out_of_range,、,range_error,、,runtime_error,等。,10/8/2024,49,range_error,overflow_error,exception,bad_typeid,runtime_error,bad_cast,ios_base:failure,logic_error,bad_exception,bad_alloc,invalid_argument,out_of_range,domain_error,leng_error,underflow_error,C+,标准异常类层次结构,10/8/2024,50,5.7,综合应用实例,异常处理是在实际开发中为了避免程序出现不正常的运行情况而采用的一种机制,它要和实际开发结合起来才有实际意义。然而,为了更好的了解,C+,实际处理异常的方式,下面的例子中避开了实际的应用。仅根据程序输入的不同,进行不同的异常处理,以更好的理解,C+,的异常处理。,【,实例一,】C+,的异常处理机制例题。,#include,#include,/,此处包含例,5.10,中的,CMyException,类代码,10/8/2024,51,class,CTestClass,/,测试类,其构造函数可能抛出,int,型或,char*,型异常,public:,CTestClass(int,x),throw(int,);,void print();,private:,int,a;,;,CTestClass,:,CTestClass(int,x),throw(int,),/,可能抛出,int,型或,char*,型异常,但其本身不处理,int,类型异常,try,if(x,=0),throw 0;,if(x,1000),throw x,值太大!,;,10/8/2024,52,a = 100/x;,catch(char,* s),cout,处理了,char*,类型异常信息:,s,endl,;,void,CTestClass:print,(),cout,a,endl,;,void func8(int x),throw(CMyException,int,),/,可能抛出,CMyException,int,类型异常,CTestClass,a(x,);,a.print,();,CMyException,obj2(obj2);,10/8/2024,53,throw obj2;,void func9(),throw(char,*),/,可能抛出,char*,类型异常,char *p = new char20;,try/,可能引起异常的代码,throw error;,catch(.),/,释放申请的空间,p,后将异常继续抛出,cout,释放申请的空间,endl,;,delete p;,throw;,10/8/2024,54,void main(),try /,可能产生异常的代码,throw new CMyException(obj1);,catch(CMyException,*e),cout,“,捕获一个,CMyException,类型的异常,名称为:,GetName,(),endl,;,delete e;,try,cout,x;,func8(x);,func9();,10/8/2024,55,catch(int,x),cout,处理了,int,类型的异常:,x,endl,;,catch(char,*s),cout,处理了,char*,类型的异常,:s,endl,;,catch(CMyException,&e),cout,处理了,CMyException,类型的异常:,“,e.GetName,(),endl,;,catch(.),cout,处理了所有类型的异常!,endl,;,10/8/2024,56,cout,程序运行结束!,endl,;,程序运行结果为:,构造一个,CMyException,异常对象,名称为:,obj1,捕获到一个,CMyException,*,类型的异常,名称为:,obj1,销毁一个,CMyException,异常对象,名称为:,obj1,请输入一个,int,类型的值:,0,处理了,int,类型的异常:,0,程序运行结束!,10/8/2024,57,
展开阅读全文
相关资源
正为您匹配相似的精品文档
相关搜索

最新文档


当前位置:首页 > 管理文书 > 施工组织


copyright@ 2023-2025  zhuangpeitu.com 装配图网版权所有   联系电话:18123376007

备案号:ICP2024067431-1 川公网安备51140202000466号


本站为文档C2C交易模式,即用户上传的文档直接被用户下载,本站只是中间服务平台,本站所有文档下载所得的收益归上传人(含作者)所有。装配图网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。若文档所含内容侵犯了您的版权或隐私,请立即通知装配图网,我们立即给予删除!