1TMTONY2012C++工具2TM2Tonyvopo123@126.com异常处理命名空间3TM3Tonyvopo123@126.com在C++发展的后期,有时C++编译系统根据实际工作的需要,增加了一些功能,作为工具来使用,其中主要有模板(包括函数模板和类模板)、异常处理、命名空间和运行时类型识别,以帮助程序设计人员更方便地进行程序的设计和调试工作。1997年ANSIC++委员会将它们纳入了ANSIC++标准,建议所有的C++编译系统都能实现这些功能。这些工具是非常有用的,C++的使用者应当尽量使用这些工具。4TM4Tonyvopo123@126.com异常处理异常处理的任务程序中常见的错误有两大类:语法错误和运行错误。在编译时,编译系统能发现程序中的语法错误。在设计程序时,应当事先分析程序运行时可能出现的各种意外的情况,并且分别制订出相应的处理方法,这就是程序的异常处理的任务。5TM5Tonyvopo123@126.comBugsProgrammermademistakeLogicerrorProgrammermisunderstandtheproblemorsolutionExceptionUnusualbutpredictable.异常的特点客观存在,不能消灭但能够预测并有选择性的去处理6TM6Tonyvopo123@126.com典型的异常你知道计算机可能会耗光内存当没有更多内存空间时,你:死机通知用户并退出程序通知用户并让用户来处理采取适当的纠正行动,让用户不受干扰7TM7Tonyvopo123@126.comC++提供的异常处理机制Exception是一个对象出现意外的地方将会产生一个异常:抛出一个异常对象该对象被传递到负责意外处理的地方由负责意外处理的代码专门进行统一的异常处理异常对象包含有意外发生的详细信息8TM8Tonyvopo123@126.com常见的异常常见的异常比如:内存请求失败文件操作不成功异常的发生都在程序的较底层异常的表现都在较高层,对异常的处理逻辑也都在较高层面,特别是直接与用户打交道的代码。异常提供了一个快速的通道,把异常信息从其发生的地方直接传递到对意外进行处理的地方9TM9Tonyvopo123@126.com异常使用三部曲1.框定异常(try语句块)在祖先函数处,框定可能产生错误的语句序列,它是异常的根据,若不框定异常,则没有异常。2.定义异常处理(catch语句块)将出现异常后的处理过程放在catch块中,以便当异常被抛出,因类型匹配而捕捉时,就处理之。3.抛掷异常(throw语句)在可能产生异常的语句中进行错误检测,有错就抛掷异常10TM10Tonyvopo123@126.com异常的产生任何时候,程序在执行中遇到了非正常状况都可以抛出异常异常用throw语句抛出A*p=newA();if(p==NULL){throwOutofMemory.;}一旦抛出异常,则程序将在throw语句处跳出11TM11Tonyvopo123@126.com异常的捕捉异常也由程序员负责捕获用try{…}catch(){…}语句来捕获异常没有捕获的异常将被忽略抛掷异常voidFun(){......throw表达式;......}捕获并处理异常(多层捕获)try{}catch(OutOfMemory){…}catch(FileNotFound){…}catch(…){…}12TM12Tonyvopo123@126.com异常处理的方法函数f()捕获并处理异常函数h()引发异常函数g()……调用者异常传播方向调用关系13TM13Tonyvopo123@126.com处理除零异常9-11.#includeiostream.h2.intDiv(intx,inty);3.voidmain()4.{try5.{cout5/2=Div(5,2)endl;6.cout8/0=Div(8,0)endl;7.cout7/1=Div(7,1)endl;8.}9.catch(int)10.{coutexceptofdevidingzero.\n;}11.coutthatisok.\n;12.}13.intDiv(intx,inty)14.{if(y==0)throwy;15.returnx/y;16.}程序运行结果如下:5/2=2exceptofdevidingzero.thatisok.14TM14Tonyvopo123@126.com异常处理的语法throw语句一般是由throw运算符和一个数据组成的,其形式为throw表达式;try-catch的结构为try{被检查的语句}catch(异常信息类型[变量名]){进行异常处理的语句}15TM15Tonyvopo123@126.com说明:(1)被检测的函数必须放在try块中,否则不起作用。(2)try块和catch块作为一个整体出现,catch块是try-catch结构中的一部分,必须紧跟在try块之后,不能单独使用,在二者之间也不能插入其他语句。但是在一个try-catch结构中,可以只有try块而无catch块。即在本函数中只检查而不处理,把catch处理块放在其他函数中。(3)try和catch块中必须有用花括号括起来的复合语句,即使花括号内只有一个语句,也不能省略花括号。(4)一个try-catch结构中只能有一个try块,但却可以有多个catch块,以便与不同的异常信息匹配。16TM16Tonyvopo123@126.com(5)catch后面的圆括号中,一般只写异常信息的类型名,如catch(double)catch只检查所捕获异常信息的类型,而不检查它们的值。因此如果需要检测多个不同的异常信息,应当由throw抛出不同类型的异常信息。异常信息可以是C++系统预定义的标准类型,也可以是用户自定义的类型(如结构体或类)。如果由throw抛出的信息属于该类型或其子类型,则catch与throw二者匹配,catch捕获该异常信息。catch还可以有另外一种写法,即除了指定类型名外,还指定变量名,如catch(doubled){cout″throw″d;}这时会输出d的值(也就是a值)。当抛出的是类对象时,有时希望在catch块中显示该对象中的某些信息。这时就需要在catch的参数中写出变量名(类对象名)。17TM17Tonyvopo123@126.com(6)如果在catch子句中没有指定异常信息的类型,而用了删节号“…”,则表示它可以捕捉任何类型的异常信息,如catch(…){cout″OK″endl;}它能捕捉所有类型的异常信息,并输出″OK″。这种catch子句应放在trycatch结构中的最后,相当于“其他”。如果把它作为第一个catch子句,则后面的catch子句都不起作用。(7)trycatch结构可以与throw出现在同一个函数中,也可以不在同一函数中。当throw抛出异常信息后,首先在本函数中寻找与之匹配的catch,如果在本函数中无trycatch结构或找不到与之匹配的catch,就转到离开出现异常最近的trycatch结构去处理。(8)在某些情况下,在throw语句中可以不包括表达式,如throw;表示“我不处理这个异常,请上级处理”。(9)如果throw抛出的异常信息找不到与之匹配的catch块,那么系统就会调用一个系统函数terminate,使程序终止运行。18TM18Tonyvopo123@126.com在函数声明中进行异常情况指定为便于阅读程序,C++允许在声明函数可能抛掷的所有异常类型。例如:voidfun()throw(A,B,C,D);若无异常接口声明,则此函数可以抛掷任何类型的异常。不抛掷任何类型异常的函数声明如下:voidfun()throw();19TM19Tonyvopo123@126.com在异常处理中处理析构函数这是一个为说明在异常处理中调用析构函数的示例,为了清晰地表示流程,程序中加入了一些cout语句,输出有关的信息,以便对照结果分析程序。9-21.#includeiostream2.#includestring3.usingnamespacestd;4.classStudent5.{public:6.Student(intn,stringnam)//定义构造函数7.{cout″constructor-″nendl;8.num=n;name=nam;}9.~Student(){cout″destructor-″numendl;}//定义析构函数10.voidget_data();//成员函数声明11.private:12.intnum;13.stringname;14.};20TM20Tonyvopo123@126.com1.voidStudent::get_data()//定义成员函数2.{if(num==0)thrownum;//如num=0,抛出int型变量num3.elsecoutnum″″nameendl;//若num≠0,输出num,name4.cout″inget_data()″endl;//输出信息,表示目前在get_data函数中5.}6.voidfun()7.{Studentstud1(1101,″Tan″);//建立对象stud18.stud1.get_data();//调用stud1的get_data函数9.Studentstud2(0,″Li″);//建立对象stud210.stud2.get_data();//调用stud2的get_data函数11.}12.intmain()13.{cout″mainbegin″endl;//表示主函数开始了14.cout″callfun()″endl;//表示调用fun函数15.try16.{fun();}//调用fun函数21TM21Tonyvopo123@126.com1.catch(intn)2.{cout″num=″n″,error!″endl;}//表示num=0出错3.cout″mainend″endl;//表示主函数结束4.return0;5.}程序运行结果如下:mainbegincallfun()constructor-11011101taninget_data()constructor-0destructor-0destructor-1101num=0,error!mainend22TM22Tonyvopo123@126.com自定义异常用户自定义的异常自己定义OutOfRange类并抛出一个OutOfRange对象作为异常23TM23Tonyvopo123@126.com自定义异常类1.不继承exception类,自定义异常类:classE1{private:constchar*message;public:E1(){message=“E1提示:年龄太大”}constchar*mywhat()const{returnmessage}};2.继承exception类,自定义异常类classE2:publicexception{private:constchar*message;public:E1(){char=“E2提示:年龄错”}constchar*what()const{char=“E2提示:年龄太小”};}24TM24Tonyvopo123@126.comInnerclassexampleexcpt.cc#includeiostream9-3usingnamespacestd;classMyClass{intscore;public:classi