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

上传人:本田雅阁 文档编号:3479321 上传时间:2019-09-01 格式:PPT 页数:57 大小:183.52KB
返回 下载 相关 举报
C程序设计课件(第5章).ppt_第1页
第1页 / 共57页
C程序设计课件(第5章).ppt_第2页
第2页 / 共57页
C程序设计课件(第5章).ppt_第3页
第3页 / 共57页
C程序设计课件(第5章).ppt_第4页
第4页 / 共57页
C程序设计课件(第5章).ppt_第5页
第5页 / 共57页
点击查看更多>>
资源描述

《C程序设计课件(第5章).ppt》由会员分享,可在线阅读,更多相关《C程序设计课件(第5章).ppt(57页珍藏版)》请在三一文库上搜索。

1、2019/9/1,1,第5章 异常处理,本章学习重点掌握内容: 异常的概念、异常的产生 异常的处理机制 throw、try和catch的用法 捕捉所有的异常 异常信号的传递方式 标准C+库的异常类,2019/9/1,2,第5章 异常处理,5.1 异常的概念 5.2 异常处理机制 5.3 没有被捕捉的异常 5.4 catch(.)使用 5.5 用类的对象传递异常 5.6 标准C+库中的异常类 5.7 综合应用实例,2019/9/1,3,5.1 异常的概念,5.1.1 异常的概念 程序运行过程中,由于环境变化、用户操作失误以及其它方面的原因而产生的运行时不正常的情况,它要求程序立即进行处理,否则将

2、会引起程序错误甚至崩溃的现象。 常见的异常有:空闲内存耗尽、请求打开不存在的文件、被0除、打印机未打开、数组越界访问等。,2019/9/1,4,5.1.2 异常的产生,C+程序是由一些相互分离的模块组成的,程序中出现错误和解决出现的错误就会分成两个部分: (1)某个模块A出现错误,但它并没有能力在模块A内解决这个错误,因此它就给出关于这个错误的报告。 (2)某个模块B能够检测到模块A发出的错误报告,并处理这个错误,使出现错误造成的损失减到最小。,2019/9/1,5,5.2 异常处理机制,5.2.1 基本概念 1抛出异常 如果程序发生异常情况,而在当前的上下文环境中获取不到处理这个异常的足够信

3、息,程序将创建一个包含出错信息的对象并将该对象抛出当前上下文环境,将错误信息发送到更大的上下文环境中,这个过程称为抛出(throw)异常。,2019/9/1,6,5.2.1 基本概念,2捕捉异常 对于一个抛出的异常,如果某一个模块能够(或想要)处理这个异常,它就可以获得程序的控制权处理该异常,这个过程称为捕捉(catch)异常。 3处理异常 当某个catch块捕捉到异常后,它就根据事先制定的策略对异常进行处理,这就是处理异常。在C+中,只有catch块能够捕获异常并进行处理,因此catch块又称为异常处理器。,2019/9/1,7,5.2.1 基本概念,4C+的异常处理机制 C+的异常处理机制

4、就是将抛出异常与捕捉异常、处理异常分离开来。抛出异常的模块并不负责异常的处理,它只是报告某个地方存在错误,这个报告可以帮助异常处理器解决这个错误。而异常处理器则根据抛出异常模块的报告来处理异常,如果没有模块抛出异常,就不会有异常的处理。,2019/9/1,8,5.2.2 throw语句,抛出异常的语法格式如下: throw 表达式 这里,throw后的表达式表示异常的类型,它可以是一个变量或一个对象。throw语句在语法上与return语句相似。下面是两条throw语句的例子。 throw 1; throw ( “出现异常”); 异常抛出后,程序的控制权就从异常抛出的地方交出,由编译器寻找匹配

5、的异常处理器进行相应的处理。,2019/9/1,9,5.2.3 try块,try块的语法格式如下: try 复合语句 try块必须包围能够抛出异常的语句。它提示编译器到那里查找异常处理器,没有跟在try块后的catch块是没有用的。 try块可以包含任何C+语句,甚至包含整个函数。,2019/9/1,10,5.2.4 catch块,catch块的语法格式如下。 catch(异常类型声明) 异常处理语句 catch(异常类型声明) 异常处理语句 ,2019/9/1,11,5.2.4 catch块,catch 后括号中的异常类型声明可以是一个类型或一个对象声明,后边一对“”括住的是一组复合语句。一

6、个catch块相当于一个以类型为单一参数的函数。 catch块必须直接放在try块之后。catch语句与switch语句不同,它不需要在每个case语句后加入break用以中断后面程序的执行。 一个catch 块引入一个局部域,在catch块内声明的变量不能在catch 块外引用。,2019/9/1,12,【例5.2】局部域声明的变量不能被局部域外引用例题。 #include void main() try /一段可能引起异常的代码 throw (“出现异常!“); catch (char* message) int y = 1; cout“处理了char*类型的异常“endl; coutye

7、ndl; /编译错误,变量y未定义 ,2019/9/1,13,5.2.5 异常处理模式,C+的异常处理有两种基本模式: 1终止模式 异常抛出后,捕捉异常并退出导致异常的子程序或子系统,退出需要关闭适当的文件,析构适当的对象,释放适当的内存,处理需要处理的设备等,这种方法称为终止模式。 缺省情况下,C+异常处理机制采用终止方法。 【例5.3】捕捉异常后直接退出的例题。,2019/9/1,14,#include void func2() /一段有可能引起异常的代码 throw 1; cout“其它程序语句!“endl; void main() try ,2019/9/1,15,func2 ();

8、/ func2 ()抛出的异常值为1 /程序抛出异常后的语句部分 cout“异常处理结束后继续执行!“endl; catch (int x) /对异常的处理 cout“处理了int类型的异常“endl; cout“程序结束!“endl; 在采用终止模式情况下程序的运行结果为: 处理了int类型的异常! 程序结束!,2019/9/1,16,5.2.5 异常处理模式,2恢复模式 异常抛出后,捕捉异常并试图去纠正或调整引起异常的条件,然后从发生异常的地方继续执行,这种方法称为恢复模式。 恢复模式实现起来非常困难,在实际应用中,除了一些特殊的领域外,一般都不采用恢复模式处理异常。,2019/9/1,1

9、7,5.2.6 重新抛出,在异常处理过程中也可能存在“单个catch子句不能完全处理这个异常”的情况。那么该异常处理器在做完局部能够做的事情后,会再一次抛出这个异常,让函数调用链中更上级的函数来处理,这个过程称作重新抛出(rethrow) 重新抛出的语法形式如下: throw; 重新抛出的还是原来捕捉到的那个异常。重新抛出只能出现在catch块中。,2019/9/1,18,【例5.4】重新抛出捕捉的异常例题。 #include void func3(int x) try / 一段有可能引起异常的代码 throw x; catch (int x) /如果异常参数x=0则进行处理,否则继续抛出 i

10、f(x=0) /对异常的处理 else cout“重新抛出异常!“endl;,2019/9/1,19,throw; /重新抛出 void main() try func3 (1); /程序其它部分 catch (int x) /对异常的处理 cout“处理了int类型的异常!“endl; ,2019/9/1,20,程序运行结果为: 重新抛出异常! 处理了int类型的异常! 有的情况下,异常处理器在重新抛出之前会对异常信号进行一些修改,这个修改能够影响更高级函数调用链中的异常处理器对该异常的处理。,5.2.6 重新抛出,2019/9/1,21,5.2.7异常规范,异常规范规定:随着函数声明列出该

11、函数可能抛出的异常,并保证该函数不会抛出其它类型的异常。常见附带异常说明的函数说明有以下3种情况。 (1)函数返回类型 函数名(参数列表)throw(类型列表); (2)函数返回类型 函数名(参数列表) throw(); (3)函数返回类型 函数名(参数列表); 第一种情况,函数列出所有可能抛出的异常类型;第二种情况表示函数不会抛出任何类型的异常;第三种情况表示函数可能抛出任何类型的异常。 异常规范并非强制规定,因此,没有在函数说明后附带异常说明并非语法错误。,2019/9/1,22,【例5.6】异常规范的处理例题 void func5(int x) throw(int, char*) /x等

12、于0抛出int型异常,x小于0抛出char*型异常,x大于0 /什么也不做 if(x=0) throw 0; if(x0) throw “error“; void func6() throw() /本函数完成10个指令周期的延时,不抛出任何异常 int i = 0; while(i10) i+; ,2019/9/1,23,5.2.7异常规范,有时,函数可能抛出没有列入异常规范的异常,出现这种情况时,系统分两种情况进行处理。 (1)在函数内部(包括抛出异常的函数以及调用该函数的函数链中的任意函数)捕捉到了这个异常,进行了处理,则程序可以继续执行。 (2)异常被抛到函数外部,系统会调用C+标准库中

13、定义的函数unexpected(),该函数的缺省行为是调用terminate(),终止程序的运行。当然,在C+中,可以改变unexpected()的缺省行为。,2019/9/1,24,5.3 没有被捕捉的异常,根据异常匹配的规则,如果try块后面的所有的catch块都没有与某一异常相匹配,这时内层对异常的捕获失败,异常将进入更高层的上下文环境中进行匹配,这个过程一直进行直到在某个层次异常处理器与该异常相匹配,这时才认为捕获了这个异常。,2019/9/1,25,5.3 没有被捕捉的异常,如果任意层的异常处理器都没有捕获到这个异常,那么这个异常最终会抛给main()函数,如果在main()中还没有

14、找到合适的匹配,则称这个异常是“未捕捉的”或“未处理的”。如果一个异常未被捕捉,就会调用函数terminate(),终止本程序的运行。,2019/9/1,26,【例5.7】未被捕捉的异常处理例题 #include void func7() throw 0; void main() try func7(); catch (double d) cout“进行了异常处理!“endl; ,2019/9/1,27,例子5.7中,func7()函数中抛出了int型的异常,最后抛给了main()函数,在main()函数中也没找到合适的匹配,于是终止本程序运行,main()函数catch块后边的程序其它部分不

15、再执行。 如果在所有函数之外的代码出现异常,比如全局对象的构造和析构等,如果有相应的异常处理器捕捉到抛出的异常,则异常处理后继续main()函数的执行,如果没有捕捉到抛出的异常,则终止本程序运行。,5.3 没有被捕捉的异常,2019/9/1,28,5.4 catch(.)使用,C+在异常处理中提供了一个能捕捉所有异常的catch块。catch块的语法格式如下: catch() 异常处理语句 其中,列表中的“”表示可捕获所有的异常,但使用省略号就不可能有参数,也不可能知道所接受到的异常为何种类型。其它部分和普通catch块完全一样。,2019/9/1,29,【例5.9】使用catch(.)语句的

16、异常处理例题 #include void func5(int x) throw(int) /x等于0抛出int型异常,x小于0抛出char*型异常 if(x=0) throw 0; if(xx;,2019/9/1,30,func5(x); /程序其它部分 catch(.) /对异常的处理 cout“处理了所有类型的异常!“endl; cout“程序结束!“endl; 程序运行结果如下: 请输入一个int类型数据:0 处理了所有类型的异常!,2019/9/1,31,5.5 用类的对象传递异常,异常信息传递是指将throw语句抛出的异常参数传递到catch块中。但在实际应用中,由于抛出异常信息的需

17、要,经常使用类的对象传递异常。使用对象传递异常还有以下2个好处: (1)在C+中,很好地实现了RTTI(Run-Time Type Information)技术,使用对象传递异常,可以很好地完成异常对象的类型匹配。 (2)在C+中,很好地实现了对象的构造、销毁、转存复制等技术,可以很好的实现异常信息的传递、修改和销毁等。 同函数参数传递方式一样,异常参数的传递有3种方式:传值方式、引用方式和指针方式,2019/9/1,32,5.5.1 传值方式传递异常对象,按传值方式传递异常对象时,被抛出的异常都是局部变量,而且是临时的局部变量。也就是说,每当在throw语句抛出一个异常对象时,不管构造的对象

18、是什么性质的变量,此时它都会复制一份临时局部变量。 【例5.10】按传值方式传递异常对象例题。 #include #include using namespace std;,2019/9/1,33,class CMyException /异常类,该类的对象作为抛出异常时传递的异常参数。 public: CMyException (string n=“none“) : name(n) /根据参数n构造一个名字为n的异常类对象 cout“构造一个CMyException对象,名称 为:“nameendl; CMyException (const CMyException ,2019/9/1,34,

19、virtual CMyException () cout “销毁一个CMyException对象,名称 为:“ name endl; string GetName() return name; protected: string name; /异常类对象的名字 ; void main() try / 构造一个异常对象,这是个局部变量。 CMyException obj1(“obj1“);,2019/9/1,35,/下面抛出异常对象。注意:这时VC编译器会复制 /一份新的异常对象,即调用一次CMyException /类的拷贝构造函数。新拷贝的对象是个临时变量。 throw obj1; catc

20、h(CMyException e) /当异常参数传递给e时,由于是传值方式,因 /此会调用一次拷贝构造函数 cout“捕获一个CMyException类型异常, 名称为:“e.GetName()endl; cout“程序运行结束!“ endl; ,2019/9/1,36,5.5.1 传值方式传递异常对象,程序运行的结果为: 构造一个CMyException对象,名称为:obj1 拷贝一个CMyException对象,名称为:obj1 拷贝一个CMyException对象,名称为:obj1 销毁一个CMyException对象,名称为:obj1 捕获到一个CMyException类型的异常,名称

21、为:obj1 销毁一个CMyException对象,名称为:obj1 销毁一个CMyException对象,名称为:obj1 程序运行结束!,2019/9/1,37,5.5.1 传值方式传递异常对象,例5.10中,调用了1次CMyException类的构造函数,2次CMyException类的拷贝构造函数。 在main() 的try块中,定义对象obj1时,调用1次CMyException类的构造函数。 通过throw语句抛出异常对象obj1时,复制了一份obj1的临时局部变量,调用1次CMyException类的拷贝构造函数 找到匹配的catch块后,由于是按值传递异常参数,又调用一次CMy

22、Exception类的拷贝构造函数。,2019/9/1,38,5.5.1 传值方式传递异常对象,例5.10中,调用了3次CMyException类的析构函数。 在进入catch块之后,进行异常处理之前,调用了一次CMyException类的析构函数,这时析构的是try块中定义的局部变量obj1。 在离开catch块时,又调用了两次CMyException类的析构函数,先析构的是进入catch块是构造的异常参数obj1,然后再析构throw语句创建的临时局部变量obj1。,2019/9/1,39,5.5.2 引用方式传递异常对象,按引用方式传递异常对象时,被抛出的异常也是临时局部变量。 【例5.

23、11】按引用方式传递异常对象的例题。 #include #include using namespace std; /插入例5.10中CMyException类的定义 void main() try / 构造一个异常对象,这是个局部变量。 CMyException obj1(“obj1“);,2019/9/1,40,/这里抛出异常对象。注意:这时VC编译器会复制 /一份新的异常对象,即调用一次CMyException / 类的拷贝构造函数。新拷贝的对象是个临时变量。 throw obj1; catch(CMyException ,2019/9/1,41,5.5.2 引用方式传递异常对象,程序运

24、行的结果为: 构造一个CMyException异常对象,名称为:obj1 拷贝一个CMyException异常对象,名称为:obj1 销毁一个CMyException异常对象,名称为:obj1 捕获到一个CMyException类型的异常,名称为:obj1 销毁一个CMyException异常对象,名称为:obj1,2019/9/1,42,5.5.2 引用方式传递异常对象,例5.11中,调用了2次CMyException类的构造函数。 在main() 的try块中,定义对象obj1时,调用1次 CMyException类的构造函数。 通过throw语句抛出异常对象obj1时,复制了一份obj1

25、的临时局部变量,调用1次CMyException类的拷贝构造函数 由于catch块是按引用方式传递异常对象,传递给catch块的是临时异常对象的引用,因而不需要调用异常类的构造函数。,2019/9/1,43,5.5.2 引用方式传递异常对象,在例5.11中,调用了2次CMyException类的析构函数。 在进入catch块之后,进行异常处理之前,调用了一次CMyException类的析构函数,这时析构的是try块中定义的局部变量obj1。 在退出catch块时,又调用了一次CMyException类的析构函数,这时析构的是调用throw语句时构建的临时异常对象。,2019/9/1,44,5.

26、5.3 指针方式传递异常对象,与传值方式和引用方式传递异常对象相比,在按指针方式传递异常时,异常对象的构造方式有很大的不同。它要么是在堆中动态构造的异常对象,要么是静态全局对象,而不能是局部变量。 【例5.12】按引用方式传递异常的例题。 #include #include using namespace std; /插入例5.10中CMyException类的定义 void main() ,2019/9/1,45,try/ 动态在堆中构造的异常对象,调用一次构造函数。 throw new CMyException (“obj1“); / 注意:这里是定义了按指针方式传递异常对象 catch(

27、CMyException* e) / 此处传递给e的实际是上面动态对象的地址, /因此不调用任何构造函数。 coutGetName()endl; delete e; /动态创建的对象需要销毁 程序运行的结果为: 构造一个CMyException异常对象,名称为:obj1 捕获到一个CMyException*类型的异常,名称为:obj1 销毁一个CMyException异常对象,名称为:obj1,2019/9/1,46,5.5.3 指针方式传递异常对象,例5.12中,只在异常抛出时调用了一次CMyException类的构造函数。 动态地创建对象,也要动态的销毁,因此,在退出catch块之前调用d

28、elete语句销毁异常对象时调用了一次 CMyException类的析构函数。,2019/9/1,47,5.5.4 异常对象传递方式的比较,2019/9/1,48,5.5.4 异常对象传递方式的比较,2019/9/1,49,5.6 标准C+库中的异常类,在标准C+库中提供了一个异常类的基类exception和它的多个派生类。分别介绍如下。 1. 头文件中定义了异常类exception和bad_exception,异常类exception是标准C+库中所有异常类的基类。 2. 头文件中定义了异常类ios_base:failure。 3. 头文件中定义了异常类bad_cast和bad_typeid

29、,当dynamic_cast失败时将抛出该异常类对象。 4. 头文件中定义了其它所有的异常类,如logic_error 、out_of_range 、range_error、runtime_error等。,2019/9/1,50,2019/9/1,51,5.7 综合应用实例,异常处理是在实际开发中为了避免程序出现不正常的运行情况而采用的一种机制,它要和实际开发结合起来才有实际意义。然而,为了更好的了解C+实际处理异常的方式,下面的例子中避开了实际的应用。仅根据程序输入的不同,进行不同的异常处理,以更好的理解C+的异常处理。 【实例一】C+的异常处理机制例题。 #include #include

30、 /此处包含例5.10中的CMyException类代码,2019/9/1,52,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(x1000) throw “x值太大!“;,2019/9/1,53,a = 100/x;

31、catch(char* s) cout“处理了char*类型异常信息:“sendl; void CTestClass:print() coutaendl; void func8(int x) throw(CMyException, int) / 可能抛出CMyException, int类型异常 CTestClass a(x); a.print(); CMyException obj2(“obj2“);,2019/9/1,54,throw obj2; void func9() throw(char*) / 可能抛出char*类型异常 char *p = new char20; try/可能引起

32、异常的代码 throw “error“; catch(.) / 释放申请的空间p后将异常继续抛出 cout “释放申请的空间“endl; delete p; throw; ,2019/9/1,55,void main() try /可能产生异常的代码 throw new CMyException(“obj1“); catch(CMyException *e) coutGetName()x; func8(x); func9(); ,2019/9/1,56,catch(int x) cout“处理了int类型的异常:“xendl; catch(char *s) cout“处理了char*类型的异常:“sendl; catch(CMyException ,2019/9/1,57, cout“程序运行结束!“ endl; 程序运行结果为: 构造一个CMyException异常对象,名称为:obj1 捕获到一个CMyException*类型的异常,名称为:obj1 销毁一个CMyException异常对象,名称为:obj1 请输入一个int类型的值:0 处理了int类型的异常:0 程序运行结束!,

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 其他


经营许可证编号:宁ICP备18001539号-1