版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
C++面向对象程序设计第10章异常处理2023/2/51燕京理工学院第10章异常处理本章学习要点一个好的程序不仅要保证能实现所需要的功能,而且还应该有很好的容错能力。在程序运行过程中如果有异常情况出现,程序本身应该能解决这些异常,而不是死机。本章介绍异常处理的基本概念、C++异常处理语句、析构函数与异常处理。通过本章的学习,掌握了C++异常处理的机制,我们就可以在编制程序时灵活地加以运用,从而使我们编制的程序在遇到异常情况时能摆脱大的影响,避免出现死机等现象。2023/2/52燕京理工学院第10章异常处理10.1C++异常处理概述10.2C++异常处理的实现10.3异常与函数10.4异常与类10.5图书馆图书借阅管理系统中的异常处理2023/2/53燕京理工学院10.1C++异常处理概述程序中常见的错误有两大类:语法错误和运行错误。在编译时,编译系统能发现程序中的语法错误(如关键字拼写错误,变量名未定义,语句末尾缺分号,括号不配对等),程序员通过错误提示可以进行修改。2023/2/54燕京理工学院有的程序虽然能通过编译,也能投入运行,但是在运行过程中会出现异常,得不到正确的运行结果,甚至导致程序不正常终止或出现死机现象,这些都说明程序中存在运行错误。运行错误相对来说比较隐蔽,是程序调试中的一个难点,该错误又可分为逻辑错误和运行异常两类。逻辑错误是由设计不当造成的,如对算法理解有误、在一系列计算过程中出现除数为0、数组的下标溢出等。这些错误只要我们在编程时多加留意是可以避免的。但是,运行异常是由系统运行环境造成的,导致程序中内存分配、文件操作及设备访问等操作的失败,可能会造成系统运行失常并瘫痪。10.1异常处理的概念及C++异常处理的基本思想2023/2/55燕京理工学院在运行没有异常处理的程序时,如果运行情况出现异常,由于程序本身不能处理,程序只能终止运行。如果在程序中设置了异常处理,则在运行情况出现异常时,由于程序本身已设定了处理的方法,于是程序的流程就转到异常处理代码段处理。需要说明的是:只要程序运行时出现与人们期望的情况不同,都可以认为是异常,并对它进行异常处理。因此,所谓异常处理是指对程序运行时出现的差错以及其他例外情况的处理。10.1异常处理的概念及C++异常处理的基本思想2023/2/56燕京理工学院10.2异常处理的实现1.异常处理语句C++处理异常的机制由3个部分组成:检查(try)、抛出(throw)和捕捉(catch)。把需要检查的语句放在try块中,throw用来当出现异常时抛出一个异常信息,而catch则用来捕捉异常信息,如果捕捉到了异常信息,就处理它。try-throw-catch构成了C++异常处理的基本结构。2023/2/57燕京理工学院10.2异常处理的实现1.异常处理语句try-throw-catch结构形式如下:try{…if(表达式1)throwx1…if(表达式2)throwx2…if(表达式n)throwxn…}catch(异常类型声明1){异常处理语句序列}catch(异常类型声明2){异常处理语句序列}…catch(异常类型声明n){异常处理语句序列}2023/2/58燕京理工学院在try-throw-catch结构中,try语句块内为需要受保护的待检测异常的语句序列,如果怀疑某段程序代码在执行时有可能发生异常,就将它放入try语句块中。当这段代码的执行出现异常时,即某个if语句中的表达式的值为真时,会用其中的throw语句来抛掷这个异常。10.2异常处理的实现2023/2/59燕京理工学院throw语句语法:throw表达式;throw语句是在程序执行发生了异常时用来抛掷这个异常的,其中表达式的值可以是int、float、字符串、类类型等,把异常抛掷给相应的处理者,即类型匹配的catch语句块。如果程序中有多处需要抛掷异常,应该用不同类型的操作数来互相区别。throw抛出的异常,通常是被catch语句捕获。10.2异常处理的实现2023/2/510燕京理工学院catch语句块是紧跟在try语句块后面的,即try块和catch块作为一个整体出现,catch块是try-catch结构中的一部分,必须紧跟在try块之后,不能单独使用,在二者之间也不能插入其他语句。但是在一个try-catch结构中,可以只有try块而无catch块。即在本函数中只检查而不处理,把catch块放在其他函数中。一个try-catch结构中只能有一个try块,但却可以有多个catch块,以便与不同类型的异常信息匹配。在执行try块中的语句时如果出现异常执行了throw语句,系统会根据throw抛出的异常信息类型按catch块出现的次序,依次检查每个catch参数表中的异常声明类型与抛掷的异常信息类型是否匹配,当匹配时,该catch块就捕获这个异常,执行catch块中的异常处理语句来处理该异常。10.2异常处理的实现2023/2/511燕京理工学院在catch参数表中,一般只写异常信息的类型名,如:catch(double)。系统只检查所抛掷的异常信息类型是否与catch参数表中的异常声明类型相匹配,而不检查它们的值。假如变量a,b,c都是int型,即使它们的值不同,在throw语句中写throwa、throwb或throwc的作用也均是相同的。因此,如果需要检测多个不同的异常信息,应当由throw抛出不同类型的异常信息。10.2异常处理的实现2023/2/512燕京理工学院异常信息类型可以是C++系统预定义的标准类型,也可以是用户自定义的类型(如结构体或类)。如果由throw抛出的异常信息属于该类型或其子类型,则catch与throw二者匹配,catch捕获该异常信息。注意:系统在检查异常信息数据类型的匹配时,不会进行数据类型的默认转换,只有与所抛掷的异常信息类型精确匹配的catch块才会捕获这个异常。10.2异常处理的实现2023/2/513燕京理工学院在catch参数表中,除了指定异常信息的类型名外,还可以指定变量名,如:catch(doubled)。此时,如果throw抛出的异常信息是double型的变量a,则catch在捕获异常信息a的同时,还使d获得a的值。如果我们希望在捕获异常信息时,还能利用throw抛出的异常信息的值,这时就需要在catch参数表中写出变量名。如:catch(doubled){cout<<"throw"<<d;}这时会输出d的值(也就是a值)。10.2异常处理的实现2023/2/514燕京理工学院当抛出的是类对象时,有时希望在catch块中显示该对象中的某些信息。【例10-1】求解一元二次方程ax2+bx+c=0。其一般解为,但若a=0或b2-4ac<0时,用此公式计算会出错。编程序,从键盘输入a,b,c的值,求x1和x2。如果a=0或b2-4ac<0,输出出错信息。
程序代码参见教材P31710.2异常处理的实现2023/2/515燕京理工学院现在结合程序分析异常处理的进行情况。(1)首先在try后面的花括号中放置上可能出现异常的语句块或程序段。(2)程序运行时将按正常的顺序执行到try块,执行try块中花括号内的语句。如果在执行try块内的语句过程中没有发生异常,则忽略所有的catch块,流程转到catch块后面的语句继续执行。如【例10-1】运行情况的第①种情况。10.2异常处理的实现2023/2/516燕京理工学院(3)如果在执行try块内的语句过程中发生异常,则由throw语句抛出一个异常信息。throw语句抛出什么样的异常由程序设计者自定,可以是任何类型的异常,在【例10-1】中抛出了整型和字符串类型的异常。10.2异常处理的实现2023/2/517燕京理工学院(4)这个异常信息提供给try-catch结构,系统会寻找与之匹配的catch块。如果某个catch参数表中的异常声明类型与抛掷的异常类型相匹配,该catch块就捕获这个异常,执行catch块中的异常处理语句来处理该异常。只要有一个catch块捕获了异常,其余的catch块都将被忽略。如【例10-1】运行情况的第②种情况,由try块内的throw语句抛掷一个整型异常,被第一个catch块捕获。【例10-1】运行情况的第③种情况,由try块内的throw语句抛掷一个字符串类型异常,被第二个catch块捕获。10.2异常处理的实现2023/2/518燕京理工学院当然,异常类型可以声明为省略号(…),表示可以处理任何类型的异常。需要说明的是,catch(…)语句块应该放在最后面,因为如果放在前面,它可以用来捕获任何异常,那么后面其他的catch语句块就不会被检查和执行了。(5)在进行异常处理后,程序并不会自动终止,继续执行catch块后面的语句。10.2异常处理的实现2023/2/519燕京理工学院(6)如果throw抛掷的异常信息找不到与之匹配的catch块,则系统就会调用一个系统函数terminate,在屏幕上显示“abnormalprogramtermination”,并终止程序的运行。10.2异常处理的实现2023/2/520燕京理工学院(7)抛掷异常信息的throw语句可以与try-catch结构出现在同一个函数中,也可以不出现在同一函数中。在这种情况下,当throw抛出异常信息后,首先在本函数中寻找与之匹配的catch块,如果在本函数中无try-catch结构或找不到与之匹配的catch块,就转到离开出现异常最近的try-catch结构去处理。上面【例10-1】的程序可以修改为教材P319的代码。10.2异常处理的实现2023/2/521燕京理工学院(8)异常处理还可以应用在函数嵌套的情况下。下面以教材P320【例10-2】为例观察在函数嵌套情况下异常检测的处理情况,了解程序执行顺序。10.2异常处理的实现2023/2/522燕京理工学院2.try块的嵌套异常处理语句在一个try块中可以嵌套另一个try块。每个try块都有自己的一组catch块,来处理在该try块中抛出的异常。try块的catch块只能处理在该try块中抛出的异常。如:try//外层的try语句{…try//内层的try语句
{…}catch(elemtypea)//这个catch语句捕获在内层try块中抛出的异常
{…}…}catch(elemtypeb)//这个catch语句捕获在外层try块中抛出的异常和在内层try块中未捕获的异常{…}10.2异常处理的实现2023/2/523燕京理工学院10.3.1在函数中处理异常异常处理可以局部化为一个函数,当每次进行该函数的调用时,异常将被重置。这样编写程序能够简单明了,避免重复,请看下面的例10-3。【例10-3】check是一个检测成绩异常的函数,当成绩达到100分以上或低于60产生异常,在60和100之间的为正常成绩。10.3异常与函数2023/2/524燕京理工学院10.3异常与函数#include<iostream>usingnamespacestd;voidcheck(intscore){try{
if(score>100)throw"成绩超高!";elseif(score<60)throw"成绩不及格!";elsecout<<"thescoreisOK..."<<score<<endl;}
catch(char*s){cout<<s<<endl;}}intmain(){check(45);check(90);check(101);
system("pause")
;return0;}2023/2/525燕京理工学院10.3.2在函数调用中完成异常处理在处理异常检测时,也可以将抛掷异常的程序代码放在一个函数中,将检测处理异常的函数代码放在另一个函数中,能让异常处理更具灵活性和实用性,如例10-4所示。【例10-4】异常处理从函数中独立出来,由调用函数完成。10.3异常与函数2023/2/526燕京理工学院10.3异常与函数#include<iostream>usingnamespacestd;voidcheck(intscore){
if(score>100)throw"成绩超高!";elseif(score<60)throw"成绩不及格!";elsecout<<"thescoreisOK..."<<score<<endl;}intmain(){try{check(45);}
catch(char*s){cout<<s<<endl;}try{check(90);}
catch(char*s){cout<<s<<endl;}try{check(101);}
catch(char*s){cout<<s<<endl;}
system("pause")
;return0;}2023/2/527燕京理工学院10.3.3限制函数异常为便于阅读程序,使用户在看程序时能够知道所用的函数是否会抛出异常信息以及抛出的异常信息的类型,C++允许在函数声明时指定函数抛出的异常信息的类型,如:doubleDeta(double,double,double)throw(double);表示Deta函数只能抛出double类型的异常信息。如果写成:doubleDeta(double,double,double)throw(int,float,double,char);则表示Deta函数可以抛出int、float、double或char类型的异常信息。10.3异常与函数2023/2/528燕京理工学院10.3.3限制函数异常异常指定是函数声明的一部分,必须同时出现在函数声明和函数定义的首行中,否则编译时,编译系统会报告“类型不匹配”。如果在函数声明时不指定函数抛出的异常信息的类型,则该函数可以抛出任何类型的异常。如:intFunc(int,char);//函数Func可以抛出任何异常如果在函数声明时指定throw参数表为不包括任何类型的空表,则不允许函数抛出任何异常。如:intFunc(int,char)throw();
//不允许函数Func抛出任何异常这时即使在函数中出现了throw语句,实际上在函数执行出现异常时也并不执行throw语句,并不抛出任何异常信息,程序将非正常终止。10.3异常与函数2023/2/529燕京理工学院10.4.1构造函数、析构函数与异常处理构造函数是一个特殊的函数,对象创建时,构造函数自动被调用。如果构造函数中出现了问题,抛出了异常,会发生什么情况?请看下面的例10-5。【例10-5】类Number的私有数据成员i赋值空间是小于等于100的数,如果赋值大于100会产生异常。10.4异常与类2023/2/530燕京理工学院10.4异常与类#include<iostream>usingnamespacestd;classNumber{public:
Number(inti){cout<<"inNumberconstructor..."<<endl;
if(i>100)throwi;elsenumber=i;}~Number(){cout<<"inNumberdestructor..."<<endl;}private:
intnumber;};intmain(){try{Numberobj(111);}
catch(inte){cout<<"catchanexceptionwhenallocatedNumber"<<e<<endl;}
cout<<"intheend"<<endl;
system("pause")
;return0;}2023/2/531燕京理工学院10.4.1构造函数、析构函数与异常处理C++异常处理的强大功能,不仅在于它能够处理各种不同类型的异常,还在于它具有为异常抛出前已构造的所有局部对象自动调用析构函数的能力。10.4异常与类2023/2/532燕京理工学院10.4.2异常类1.关于异常类用来传递异常信息的类就是异常类。异常类可以非常简单,甚至没有任何成员;也可以同普通类一样复杂,有自己的数据成员、成员函数、构造函数、析构函数、虚函数等,还可以通过派生方式构成异常类的继承层次结构。下面我们首先看例10-6,程序中声明了一个没有任何成员的简单异常类。例10-7程序中声明了一个同普通类一样的有数据成员和成员函数的较复杂的异常类。10.4异常与类2023/2/533燕京理工学院10.4.2异常类1.关于异常类【例10-6】设计一个堆栈,当入栈元素超出了堆栈容量时,就抛出一个栈满的异常。10.4异常与类2023/2/534燕京理工学院#include<iostream>usingnamespacestd;constintMAX=3;classFull{}; //堆栈满时抛出的异常类classEmpty{};//堆栈空时抛出的异常类classStack{public:
Stack(){top=-1;}voidpush(inta);
intpop();private:
int
s[MAX];
inttop;};2023/2/535燕京理工学院voidStack::push(inta){
if(top>=MAX-1)throwFull();
s[++top]=a;}int
Stack::pop(){
if(top<0)throwEmpty();returns[top--];}2023/2/536燕京理工学院intmain(){Stacks;try{s.push(1);s.push(2);s.push(3);s.push(4); //将产生栈满异常
cout<<"s[0]="<<s.pop()<<endl;
cout<<"s[1]="<<s.pop()<<endl;
cout<<"s[2]="<<s.pop()<<endl;//cout<<"s[3]="<<s.pop()<<endl;//将产生栈空异常}catch(Full){cout<<"Exception:StackFull!"<<endl;}catch(Empty){cout<<"Exception:StackEmpty!"<<endl;}system("pause")
;return0;}2023/2/537燕京理工学院10.4.2异常类2.异常对象由异常类建立的对象称为异常对象。异常类的处理过程实际上就是异常对象的生成与传递过程。在编写程序时,如果发生异常,可以抛掷一个异常类对象,在catch语句中,可以输出这个异常类对象的相关信息。10.4异常与类2023/2/538燕京理工学院10.4.2异常类2.异常对象例10-7修改例10-6的Full异常类,修改后的Full类具有构造函数和成员函数getValue,还有一个数据成员a。利用这些成员,可以获取异常发生时没有入栈的元素信息。10.4异常与类2023/2/539燕京理工学院#include<iostream>usingnamespacestd;constintMAX=3;classFull{public:
Full(int
i):a(i){}
int
getValue(){returna;}private:
inta;};classEmpty{};2023/2/540燕京理工学院classStack{public:
Stack(){top=-1;}voidpush(inta){
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
评论
0/150
提交评论