下载

2下载券

加入VIP
  • 专属下载特权
  • 现金文档折扣购买
  • VIP免费专区
  • 千万文档免费下载

上传资料

关闭

关闭

关闭

封号提示

内容

首页 C++课件--薛景瑄chapter_7

C++课件--薛景瑄chapter_7.doc

C++课件--薛景瑄chapter_7

jingernanhang
2018-09-05 0人阅读 举报 0 0 0 暂无简介

简介:本文档为《C++课件--薛景瑄chapter_7doc》,可适用于IT/计算机领域

第七章异常及其处理(exceptionanditshandling)程序运行错误及其处理程序在运行中可能出错例如在除法运算中用作除数、对负数求开方根、在计算机监控系统中所采集的数据越限等等。当程序出错时一般要求用户进行处理如重新输入数值或重新采集数值等。程序首先应检测到出错然后才能提示用户进行处理或自动进行处理。传统的错误处理方式唯有依靠函数返回标志数据或者全局标志数据的改变来提示出错。这类做法的困难是程序只能在函数返回主程序处检查标志数据。如果使用全局数据则它的数据安全性差极易受到破坏。错误处理的一种新的方式是使用“异常”。异常处理是由程序设计语言提供的运行时刻错误处理的一种方式。一旦程序出现错误即引发和抛出异常程序能在一处或多处方便的地方自动地捕获异常并进行必要的处理。例求负数的开方根时传统的错误处理方式:sqrtnegativecpperroroccurswhenthesquarerootofanegativenumberiscalculatedsystemsubroutineused#include<iostreamh>#include<mathh>ptototype:doublesqrt(double)#include<stdlibh>ptototype:voidexit(int)doublesqroot(doublenumber){if(number<){cout<<"Error!negativeinputnumber:"<<number<<'n'cout<<"Programterminated!"<<'n'exit()}returnsqrt(number)systemsubroutine}voidmain(){cout<<"Sqrtofis"<<sqroot()<<endlcout<<"Sqrtofis"<<sqroot()<<endlcout<<"Sqrtofis"<<sqroot()<<endl}*Results:SqrtofisError!negativeinputnumber:Programterminated!*以上程序中当准备求取负数的平方根时就出错程序非正常结束。为使程序非正常结束须要调用系统子程序exit()其函数原型在头文件stdlibh内。例第五章§“除法运算符重载”中的程序overlddivcpp该程序中的子程序doubledivision::operator(doubledenominator){if(denominator==){cout<<"attemptedtodividebyzero"<<endlreturn}return(numeratordenominator)}将的返回值作为错误标志。voidmain(){doublenumerator,denominatordoubleresultdivisionnum(numerator)result=numdenominatorieresult=numoperator(denominator)if(result==){cout<<"Thequotientisinfinity!"<<endlcout<<"Tryagain!"<<endl}……}主函数main()在子函数doubledivision::operator(doubledenominator)返回主函数后立即检查返回值如发现出错就加以显示。如果程序中出错地方较多这类处理方法就有其局限性:当调用函数的级联数量较多(即一个函数调用下一个函数而下一个又调用再下一个的级联方式)而又需要在其它地方(例如上级的上级的上级)统一进行处理时逐级传递错误码太繁琐。因此需要借重于异常处理。请参阅本章§“抛出异常”中的例中的程序exceptioncpp。例依靠异常来处理求负数开方根的例子(当然此例中并不一定需要异常处理):exceptionsqrtcppexceptionoccurswhenthesquarerootofanegativenumberiscalculated#include<iostreamh>#include<mathh>ptototype:doublesqrt(double)#include<stdlibh>不再需要exit()doublesqroot(doublenumber){if(number<)thrownumberreturnsqrt(number)systemsubroutine}voidmain(){try{cout<<"Sqrtofis"<<sqroot()<<endlcout<<"Sqrtofis"<<sqroot()<<endlcout<<"Sqrtofis"<<sqroot()<<endl}catch(double){exceptionhandlercout<<"Error!negativeinputnumber"<<'n'cout<<"Programterminated!"<<'n'exit()因已到程序结尾故不再需要此函数}}*Results:SqrtofisError!negativeinputnumberProgramterminated!*一种较好的编程方式是首先编写正常运行的代码然后再添加用于处理各类异常情况的语句。这点将在下面叙述。异常及其处理抛出异常从上节例中可以看出当监测到程序出错时就抛出异常。其格式为:try{……监测到程序出错时throw异常对象……}其中被抛出的异常对象可以是预定义数据类型(例如int、double、char*等)的数据及其指针和引用但更经常使用的是各种异常类的对象及其指针和引用。使用这些异常类对象的优点是能够提供更多关于程序错误的信息包括处理各类错误的方法。这些异常类可以是系统所提供的更多情况下可以是用户自己定义的。应该注意:此处要求一定在try程序块中或它所调用的函数中抛出异常。以下是不在try程序块中而在try程序块所调用的函数中抛出异常的例子:例在try程序块所调用的函数quotient()中抛出异常的例子exceptioncppAsimpleexceptionhandlingexampleCheckingforadividebyzeroexceptionandthrowinganintetgerasanexception#include<iostreamh>DefinitionoffunctionquotientDemonstratesthrowinganexceptionwhenadividebyzeroexceptionisencountereddoublequotient(doublenumerator,doubledivisor){if(divisor==)throwdivisor被抛出的异常对象是预定义类型数据returnnumeratordivisor}Driverprogramvoidmain(){thetryblockwrapsthecodethatmaythrowanexceptionandthecodethatshouldnotexecuteifanexceptionoccurstry{cout<<"Thequotientofis"<<quotient(,)<<endlcout<<"Thequotientofis"<<quotient(,)<<endlcout<<"Thequotientofis"<<quotient(,)<<endl}catch(doubledd){exceptionhandlercout<<"Exception:divisor"<<dd<<"used!"<<endl}}*Results:ThequotientofisThequotientofisException:divisorused!*从以上例子中可以看出当程序不出错时程序按照顺序控制结构逐条语句地向下执行并返回除法运算结果。而当程序出错时(即当除数为零时)程序就在抛出异常处中断不再执行以后的语句并跳转至catch程序块再继续执行程序。例使用系统的异常类classexception为此须包含头文件<exception>exceptioncppsameasexceptioncpp,onlydifferinginthrowinganobjectofaclassinsteadofadoublevalue#include<iostreamh>#include<exception>DefinitionoffunctionquotientDemonstratesthrowinganexceptionwhenadividebyzeroexceptionisencountereddoublequotient(doublenumerator,doubledivisor){if(divisor==)throwexception()被抛出的异常对象是异常类即classexception的对象classexceptionisdeclaredintheincludefile<exception>returnnumeratordivisor}Driverprogramvoidmain(){thetryblockwrapsthecodethatmaythrowanexceptionandthecodethatshouldnotexecuteifanexceptionoccurstry{cout<<"Thequotientofis"<<quotient(,)<<endlcout<<"Thequotientofis"<<quotient(,)<<endlcout<<"Thequotientofis"<<quotient(,)<<endl}catch(exceptionex){exceptionhandlercout<<exwhat()<<'n'}}*Results:ThequotientofisUnknownexception*以上程序中classexception是系统所提供的异常类在抛出异常时建立该异常类exception的对象。为使用classexception在程序中应包含头文件<exception>在§中将会详细介绍它。catch程序块中内容将在下一小节§中介绍。以上程序中当出现异常时程序流即自动退出try程序块进入catch程序块进行处理后即进入catch程序块以后的语句不再继续执行try程序块中抛出异常语句后的其他语句(上例中不再执行第三条语句“……quotient(,)……”)。以上程序中无法显示异常内容但只需将以上程序略加修改即可显示异常内容。如exceptioncpp(未显示整个程序)中只需将doublequotient(intnumerator,intdivisor)函数的第一句“if(divisor==)throwexception()”改为:“if(divisor==)throwexception("dividebyzeroexception")使用系统的异常类的对象并初始化”即可!也就是在建立classexception的对象时使用字符串"dividebyzeroexception"将该异常对象初始化输入用于显示异常性质的字符串。在调用异常对象中的what()函数时就能显示该字符串。这就获得如下更明确的运行结果:*Results:ThequotientofisDividebyzeroexception*以前提到过当函数级联调用时使用显示出错的函数返回值要逐级向上递送很不方便。而使用异常处理就方便了。例函数级联调用时的异常处理exceptioncppcascadedinvocationofsubroutines#include<iostreamh>#include<exception>DefinitionoffunctionquotientDemonstratesthrowinganexceptionwhenadividebyzeroexceptionisencountereddoublequotient(doublenumerator,doubledivisor){if(divisor==)throwexception("Dividebyzeroexception")使用系统的异常类returnnumeratordivisor}doubleh(doublenumerator,doubledivisor){doubleresult=quotient(numerator,divisor)cout<<"functionh()inreturnpath!"<<endlreturnresult}doubleg(doublenumerator,doubledivisor){doubleresult=h(numerator,divisor)cout<<"functiong()inreturnpath!"<<endlreturnresult}doublef(doublenumerator,doubledivisor){doubleresult=g(numerator,divisor)cout<<"functionf()inreturnpath!"<<endlreturnresult}Driverprogramvoidmain(){thetryblockwrapsthecodethatmaythrowanexceptionandthecodethatshouldnotexecuteifanexceptionoccurstry{cout<<"Thequotientofis"<<f(,)<<endlcout<<"Thequotientofis"<<f(,)<<endlcout<<"Thequotientofis"<<f(,)<<endl}catch(exceptionex){exceptionhandlercout<<exwhat()<<'n'}}*Results:functionh()inreturnpath!functiong()inreturnpath!functionf()inreturnpath!ThequotientofisDividebyzeroexception*以上程序中正常调用函数的路径是:main()>f()>g()>h()>quotient()在函数返回时则采取相反路径即quotient()>h()>g()>f()>main()。但在出现异常时也即调用程序中一下语句cout<<"Thequotientofis"<<f(,)<<endl时就不再按步就班而是直接从quotient()返回至main()中的catch程序块。其流程如下图所示:正常运行流程引发异常流程其中表示函数调用方向表示正常返回方向表示出现异常时的返回方向捕获异常捕获异常以便进行处理时通常使用catch程序块其格式为:catch(数据或类的对象){程序块}可在该程序块中显示相关信息和进行必要处理。例使用异常检查数组下标越限exceptioncpp使用异常检查数组下标越限#include<iostreamh>doublearr={,,,,}intarr={,,,,,,,,,}intLENarraylength(numberofelements)doublef(inti){if(i>=LEN)throwireturnarri}voidmain(){ArraylengthisdeterminedfirstLEN=sizeof(arr)sizeof(arr)try{cout<<"arr="<<f()<<endlcout<<"arr="<<f()<<endlcout<<"arr="<<f()<<endl}catch(intx){cout<<"Exception:subscript"<<x<<"beyondlimit(arraylength="<<LEN<<")"<<endl}}*Results:如数组定义为doublearr={,,,,}则运行结果为:arr=Exception:subscriptbeyondlimit(arraylength=)如数组定义为intarr={,,,,,,,,,}则运行结果为:arr=arr=Exception:subscriptbeyondlimit(arraylength=)*以上程序中主程序首先自动地确定数组长度。无论该数组类型如何都可正确地求得数组长度。当下标越限时就抛出异常。稍后在catch程序块中捕获异常并显示该下标的数值。这是捕获一个异常的例子以下是捕获两个异常并作不同显示的例子:例输入两个数值两者相除求其商。如分母为零抛出第一类异常。如错误地输入错误类型的变量例如字符变量则抛出第二类异常。这两类异常由一个catch程序块捕获而能作不同显示。exceptioncppdifferentexceptionscaughtbyoneblock#include<iostreamh>#include<exception>doublequotient(doublenumerator,doubledivisor){if(divisor==)throwexception("Dividebyzeroexception")使用系统的异常类并初始化其对象returnnumeratordivisor}voidmain(){doublenumerator,divisorcout<<"Entertwointegers:"cin>>numerator>>divisortry{if(!cin)throwexception("Wronginputtypeexception")cout<<"Thequotientof"<<numerator<<''<<divisor<<"is"<<quotient(numerator,divisor)<<endlcout<<"Thequotientofis"<<quotient(,)<<endl}catch(exceptionex){exceptionhandlercout<<exwhat()<<'n'}}*Threekindsofresults:()Entertwointegers:ThequotientofisThequotientofis()Entertwointegers:Dividebyzeroexception()Entertwointegers:pWronginputtypeexception*上例中如分母为零抛出第一类异常。如错误地输入字符变量则抛出第二类异常。这两类异常由同一个程序块捕获进行处理显示不同内容:对第一类异常显示“Dividebyzeroexception”对第二类异常显示“Wronginputtypeexception”。附录十九是多个地方抛出的相同内容的异常在同一个catch程序块内处理的另一个例子。还有一种格式catch(…)可用于捕获各类异常或用于捕获其它catch()格式所不能捕获的异常。有兴趣者可参阅附录二十。C的异常处理机制可简叙如下:如果try块中没有抛出异常则所有与try块相关的catch块将被忽略程序跳过所有catch块后继续运行。catch块一般位于try块之后。如果try块中抛出异常try块中的剩余语句将被跳过而忽略。程序转至其参数类型与异常类型相匹配的catch块中由其处理该异常然后执行所有catch块以后的语句。如果没有其参数类型与异常类型相匹配的catch块则由catch(…)块处理该异常。用于处理异常的类系统提供的异常类exceptioncpp中抛出异常的语句是:if(divisor==)throwexception()而其运行结果显示异常性质为Unknownexception。而exceptioncpp(未显示整个程序)中抛出异常的语句是:if(divisor==)throwexception("dividebyzeroexception")而其运行结果显示异常性质为dividebyzeroexception。这是建立异常类的对象的两种不同方式。这是什么异常类?系统在头文件exception(不是exceptionh)中声明了用于处理异常的类exception该类的接口如下:classexception{public:exception()exception(constchar*)exception(constexception)exceptionoperator=(constexception)virtual~exception()virtualchar*what()constprivate:char*mwhatintmdoFree}exceptioncpp中抛出异常的语句是:if(divisor==)throwexception()它在建立对象时调用构造函数exception()没有任何初始化参数。而字符串“Unknownexception”则是该异常类构造函数的缺省参数。而exceptioncpp中抛出异常的语句是:if(divisor==)throwexception("dividebyzeroexception")它在建立对象时调用重载的构造函数exception(const*char)将字符串"dividebyzeroexception"用作初始化参数写入exceptionmwhat字符串中。而以后主程序中调用该对象ex的成员函数exwhat()时即在运行结果中显示该字符串指出异常性质为dividebyzeroexception。用户除使用系统的异常类之外也可自己定义该系统异常类classexception的派生类。例用户自己定义系统classexception的派生异常类exceptionderivedcppderivedclassofsystemclassexception#include<iostreamh>#include<exception>doubledivisorclassExceptderive:publicexception{char*messagepublic:Exceptderive(char*ptr){message=ptr}virtualconstchar*what()const{returnmessage}voidhandling(){cout<<"Enterdivisor(分母)again:"cin>>divisor}}voidmain(){doublenumeratorboolflag=truecout<<"Entertwodata:"cin>>numerator>>divisorwhile(flag){try{if(divisor==)throwExceptderive("dividebyzero!")cout<<"Thequotientis:"<<(numeratordivisor)<<endlflag=false}catch(Exceptderiveex){exceptionhandlercout<<"Exception:"<<exwhat()<<'n'exhandling()}}while}*Results:Entertwodata:Exception:dividebyzero!Enterdivisor(分母)again:Thequotientis:*以上程序中使用了循环方式当出现异常时可循环运行以便用户再次输入正确数据。只当输入的两个数据都正确时程序才给出运算结果并正常结束。用户自定义异常类用户也可自己定义异常类。如下例:例在给定温度条件下进行除法运算。先检查温度如温度过高或过低则调整温度至给定范围。然后在除法运算中检查零除数。异常类的基类用于处理零除数异常类的派生类则用于处理温度过高或温度过低并能自动地将温度调整度。exceptionderivedloopcppuserdefinedclassexceptanditsderivedclasses#include<iostreamh>#defineMAXT#defineMINTinttemperaturedoubledenominatorclassexcept{char*messagepublic:except(char*ptr){message=ptr}virtualconstchar*what()const{returnmessage}virtualvoidhandling(){cout<<"Enteranonzerodenominatoragain:"cin>>denominator}voidaction(){cout<<"Exception:"<<what()<<'n'handling()}}classexceptderive:publicexcept{public:exceptderive(char*ptr):except(ptr){}virtualvoidhandling(){if(temperature>MAXT)cout<<"Decreasethetemperatureto"<<(temperature=)<<endlelsecout<<"Raisethetemperatureto"<<(temperature=)<<endl}}doublequotient(doublenumerator,doubledenominator){if(denominator==)throwexcept("dividebyzero!")returnnumeratordenominator}voidmain(){doublenumerator,resultboolflag=truechar*meslow={"Temperaturetoolow!"}char*meshigh={"Temperaturetoohigh!"}cout<<"Measuretemperature:"cin>>temperaturecout<<"Enternumeratoranddenominator:"cin>>numerator>>denominatorwhile(flag){try{if((temperature>MAXT)||(temperature<MINT))throwexceptderive((temperature>MAXT)(meshigh):(meslow))result=quotient(numerator,denominator)cout<<"Thequotientis:"<<result<<endlflag=false}Thefollowingordershouldnotbereversedcatch(exceptderiveex){exaction()}catch(exceptex){exaction()}}while}*Atleastthreekindsofresults:()Measuretemperature:Enternumeratoranddenominator:Thequotientis:()Measuretemperature:Enternumeratoranddenominator:Exception:Temperaturetoohigh!DecreasethetemperaturetoException:Temperaturetoohigh!DecreasethetemperaturetoThequotientis:()Measuretemperature:Enternumeratoranddenominator:Exception:Temperaturetoolow!RaisethetemperaturetoException:Temperaturetoolow!RaisethetemperaturetoThequotientis:*当以上程序中出现异常时任何一个捕获块都调用基类的action()而此action()函数能够根据不同对象指针来调用相应的虚函数handling()实现第五章中所述“多态性”。另外同一个派生类同时用于处理温度过高或过低并区别地采取相应措施。异常类基类指针和引用的继承以上§“用户自定义异常类”例的exceptionderivedloopcpp程序中为了捕获两个不同类(基类和派生类)的对象使用两个catch程序块即:catch(exceptderiveex){exaction()}catch(exceptex){exaction()}这两个程序块的形参完全相同。能否合并为一个例如catch(…)程序块?可以!但此合并后的程序块无法捕获对象名称也就无法区别并调用相应类的对象的虚函数handling()因这涉及基类对象的继承问题。第五章中曾提到函数的“按数值调用”中派生类对象无法继承基类对象但却能继承基类对象的指针和引用。因此须求助于基类对象指针或引用。所以为了合并这两个catch程序块必须使用异常类基类的指针或引用而不是基类对象本身。如下:例异常类基类指针的继承exceptionderivedloopcppuserdefinedclassexceptanditsderivedclasses和exceptionderivedloopcpp不同之处用红笔标出#include<iostreamh>#defineMAXT#defineMINTinttemperaturedoubledenominatorclassexcept{char*messagepublic:except(char*ptr){message=ptr}virtualconstchar*what()const{returnmessage}virtualvoidhandling(){cout<<"Enteranonzerodenominatoragain:"cin>>denominator}voidaction(){cout<<"Exception:"<<what()<<'n'handling()}}classexceptderive:publicexcept{public:exceptderive(char*ptr):except(ptr){}virtualvoidhandling(){if(temperature>MAXT)cout<<"Decreasethetemperatureto"<<(temperature=)<<endlelsecout<<"Raisethetemperatureto"<<(temperature=)<<endl}}doublequotient(doublenumerator,doubledenominator){if(denominator==)thrownewexcept("dividebyzero!")此抛出语句等同于以下两句:except*ptr=newexcept("dividebyzero!")throwptrreturnnumeratordenominator}voidmain(){doublenumerator,resultboolflag=truechar*meslow={"Temperaturetoolow!"}char*meshigh={"Temperaturetoohigh!"}cout<<"Measuretemperature:"cin>>temperaturecout<<"Enternumeratoranddenominator:"cin>>numerator>>denominatorwhile(flag){try{if((temperature>MAXT)||(temperature<MINT))thrownewexceptderive((temperature>MAXT)(meshigh):(meslow))result=quotient(numerator,denominator)cout<<"Thequotientis:"<<result<<endlflag=false}catch(except*m){m>action()deletem}异常类基类对象的指针catch(exceptderiveex){exaction()}catch(exceptex){exaction()}}while}*Atleastthreekindsofresults:()Measuretemperature:Enternumeratoranddenominator:Thequotientis:()Measuretemperature:Enternumeratoranddenominator:Exception:Temperaturetoohigh!DecreasethetemperaturetoException:Temperaturetoohigh!DecreasethetemperaturetoThequotientis:()Measuretemperature:Enternumeratoranddenominator:Exception:Temperaturetoolow!RaisethetemperaturetoException:Temperaturetoolow!RaisethetemperaturetoThequotientis:*例异常类基类对象引用的继承exceptionderivedloopcppimprovedversionofexceptionderivedloopcppuserdefinedclassexceptanditsderivedclassreferencetobaseclassisusedforallderivedclassobjects和exceptionderivedloopcpp不同之处用蓝笔标出#include<iostreamh>#defineMAXT#defineMINTinttemperaturedoubledenominatorclassexcept{char*messagepublic:except(char*ptr){message=ptr}virtualconstchar*what()const{returnmessage}virtualvoidhandling(){cout<<"Enteranonzerodenominatoragain:"cin>>denominator}voidaction(){cout<<"Exception:"<<what()<<'n'handling()}}classexceptderive:publicexcept{public:exceptderive(char*ptr):except(ptr){}virtualvoidhandling(){if(temperature>MAXT)cout<<"Decreasethetemperatureto"<<(temperature=)<<endlelsecout<<"Raisethetemperatureto"<<(temperature=)<<endl}}doublequotient(doublenumerator,doubledenominator){if(denominator==){exceptref=except("dividebyzero!")throwref}returnnumeratordenominator}voidmain(){doublenumerator,resultboolflag=truechar*meslow={"Temperaturetoolow!"}char*meshigh={"Temperaturetoohigh!"}cout<<"Measuretemperature:"cin>>temperaturecout<<"Enternumeratoranddenominator:"cin>>numerator>>denominatorwhile(flag){try{if((temperature>MAXT)||(temperature<MINT)){exceptderiverefd=exceptderive((temperature>MAXT)(meshigh):(meslow))throwrefd}result=quotient(numerator,denominator)cout<<"Thequotientis:"<<result<<endlflag=false}catch(exceptex){exaction()}异常类基类对象的引用catch(exceptderiveex){exaction()}}while}*Atleastthreekindsofresults:()Measuretemperature:Enternumeratoranddenominator:Thequotientis:()Measuretemperature:Enternumeratoranddenominator:Exception:Temperaturetoohigh!DecreasethetemperaturetoException:Temperaturetoohigh!DecreasethetemperaturetoThequotientis:()Measuretemperature:Enternumeratoranddenominator:Exception:Temperaturetoolow!RaisethetemperaturetoException:Temperaturetoolow!RaisethetemperaturetoThequotientis:*上一程序中语句exceptref=except("dividebyzero!")中等式的左侧用于定义一个classexcept对象的引用ref而等式右侧则用于建立一个classexcept的对象。从以上两个程序可以看出它们的不同点:()使用异常类对象指针捕获异常时一般在堆区中分配空间因此当异常处理完毕后必须删除堆区内的异常对象否则将造成资源泄漏。()使用异常类对象引用捕获异常时由于异常类对象是在栈区中建立的因此当异常处理完毕后程序退出捕获程序块时异常对象将被自动删除。构造函数、析构函数和异常处理现在看一下异常类的构造函数和析构函数以及该异常类对象和其它类的构造函数和析构函数的关系。例自定义异常类except与构造函数和析构函数。捕获异常时使用异常类对象的指针。exceptionctordestorcpppartlycopiedfrom马光志’sbook,p#include<iostreamh>#include<stringh>classexcept自定义的异常类{charmsgpublic:except(constchar*s){strcpy(msg,s)cout<<"Exceptionconstructor"<<endl}~except(){cout<<"Exceptiondestructor:anexceptionoccuredto"<<msg<<endl}}classperson{protected:char*nameintagepublic:person(constchar*nm,intag){name=newcharstrlen(nm)strcpy(name,nm)age=ag}~person(){cout<<name<<"'s'person'destructor"<<endldeletename}voidinfo(){cout<<"name:"<<name<<endlcout<<"age:"<<age<<endl}}classadult:publicperson{char*positionpublic:adult(char*nm,char*p,intag)~adult(){cout<<name<<"'s'adult'destructor"<<endldeleteposition}voidinfo(){person::info()cout<<"position:"<<position<<endl}}adult::adult(char*nm,char*p,intag):person(nm,ag){if(ag<){cout<<name<<"'s'adult'constructorthrowsanexception"<<endlthrownewexcept(name)相等于以下三条语句:except*ptr(类似于int*ptr)ptr=newexcept(name)(类似于ptr=newint())throwptr}position=newcharstrlen(p)strcpy(position,p)}voidmain(){try{adultwang("Wang","professor",)adultwang("Wang","professor",)wanginfo()adultliu("Liu","engineer",)adultliu("Liu","engineer",)liuinfo()}catch(constexcept*m){deletem}inordertoinvokedestructor}*Threekindsofresults:()Forthecode:try{adultwang("wang","professor",)adultliu("liu","professor",)}theresultis:name:Wangage:position:professorname:Liuage:position:engineerLiu's'adult'destructorLiu's'person'destructorWang's'adult'destructorWang's'person'destructor()Forthecode:try{adultwang("Wang","professor",)adultliu("Liu","engineer",)}theresultis:Wang's'adult'constructorthrowsanexceptionExceptionconstructorWang's'person'destructorExceptiondestructor:anexceptionoccuredtoWang()Forthecode:try{adultwang("Wang","professor",)adultliu("Liu","professor",)}theresultis:name:Wangage:position:professorLiu's'adult'constructorthrowsanexceptionExceptionconstructorLiu's'person'destructorWang's'adult'destructorWang's'person'destructorExceptiondestructor:anexceptionoccuredtoLiu*在上例中classexcept是用户自己定义的异常类。用户的自定义类是基类classperson。后来由于其数据成员不够又派生出classadult。本来在基类中对年龄并无限制但在派生类中增加“职位”position后对年龄有限制要求必须大于岁。由于基类的定义不能再改就只能在派生类中检查年龄是否符合规定。因此在派生类的构造函数中检查年龄如不符合规定则抛出异常具体讲是使用new在堆区内分配一个空间放置该classexcept的对象并将它初始化。程序运行有三种情况:()建立两个用户对象时一切正常不抛出异常。程序结束时调用两个类的析构函数用于将两个类的构造函数所分配的堆区内空间退还给堆区。此种情况下共建立了两个对象:wang和liu。()建立第一个用户对象“wang”时不正常抛出异常没有分配堆区给position而只分配给name此时没有建立对象“wang”因而只调用了其基类“person”的构造函数。因此程序结束时也只调用它的基类“person”的析构函数将所分配的name空间退还给堆区而不调用它的派生类“adult”的析构函数。由于建立第一个用户对象“wang”时抛出异常因而也就不建立第二个用户对象“liu”。在抛出异常时使用new分配堆区给classexcept的对象中的msg字符串name即“wang”。所以在捕获异常时应该调用异常类对象的析构函数将该堆区空间释放掉与此同时也就显示一句“Anexceptionoccuredtowang”。此种情况下只建立了一个对象:classexcept的对象。()建立第一个用户对象“wang”时正常而建立第二个用户对象“liu”时不正常抛出异常没有分配堆区给position而只分配给name。程序结束时调用第一个对象的两个析构函数而只调用第二个对象的基类析构函数将所分配的name空间退还给堆区。在捕获异常时调用异常类对象的析构函数将该堆区空间释放掉与此同时也就显示一句“Anexceptionoccuredtoliu”。此种情况下建立了两个对象:是wang和classexcept的对象。在第二类和第三类情况中由于在构造函数中抛出异常在程序结束时无法调用其派生类的析构函数。因此必须注意:构造函数中抛出异常之前所做的工作应妥善处理就是说如在抛出异常之前调用了new则在捕获异常时必须调用delete。因此最好避免在构造函数中抛出异常。(第七章完)h()quotient()g()f()h()main()quotient()f()g()main()

用户评价(0)

关闭

新课改视野下建构高中语文教学实验成果报告(32KB)

抱歉,积分不足下载失败,请稍后再试!

提示

试读已结束,如需要继续阅读或者下载,敬请购买!

评分:

/22

VIP

在线
客服

免费
邮箱

爱问共享资料服务号

扫描关注领取更多福利