1、面向对象程序设计,八、异常处理,内容提要,程序中潜在的异常问题异常处理机制C+中的异常处理标准异常使用异常处理应注意的几个问题,提出问题,【例】求解一元二次方程ax2+bx+c=0#include#includeusing namespace std;int main()float a,b,c;double x1,x2;coutabc;x1=(-b+sqrt(b*b-4*a*c)/2*a;x2=(-b-sqrt(b*b-4*a*c)/2*a;cout方程的实根是: x1=x1 x2=x2abc;try if(0 = a) throw a;/ b并无意义,代表float型即可if(b*b-4*a
2、*c)0) throw 1.0;x1=(-b+sqrt(b*b-4*a*c)/2*b;x2=(-b-sqrt(b*b-4*a*c)/2*b;cout方程的实根是: x1=x1 x2=x2endl;catch(float)/捕获float类型的异常 cout系数b不能为0,方程无解!endl; catch(double)/捕获double类型的异常 cout开方为负值,方程无解!endl; cout程序结束!endl;return 0;,异常在多层模块间的传递,【例】函数嵌套情况下的异常处理typedef struct zero/声明除数为零异常类型string s;ZERO;typedef s
3、truct negative/声明开方值为负异常类型string s;NEGATIVE;fun2(int a,int b,int c)/抛出异常的函数ZERO s1;NEGATIVE s2; s1.s=除数为零;s2.s=开方值为负数;if(0 = a) throw s1;if(b*b-4*a*c)abc;try cout方程的一个实根是: x1=fun1(a,b,c)endl; catch(ZERO S1) /捕获除数为零异常,并处理异常 coutS1.s,方程无解!endl; catch(NEGATIVE S2)/ 捕获开方值为负数异常,并处理异常 coutS2.s,方程无解!endl;
4、cout程序结束!endl;return 0;,异常接口声明,在使用可能抛出异常的函数时,可能需要知道该函数抛出的异常类型,C+专门提供了异常接口声明,也称为异常规范。其语法形式如下:函数类型 函数名(函数参数表) throw (异常类型表)其中异常类型表包括该函数中所有可以抛出的异常类型,异常类型之间用逗号分开。异常接口声明是函数接口的一部分,是函数使用者和函数之间的协议。,异常处理中析构函数的调用,#include using namespace std;void Fun( void );class intArray public:intArray(int n) p = new int n
5、 ; cout构造intArray,分配具有”n“个元素的数组。 endl;intArray() delete p;cout 析构intArray,释放资源。 endl;private:int *p;,void Fun() intArray ia(10);cout 在Fun()中抛掷整型异常。 endl; throw 1;int main() try cout 在主函数的try块中调用函数Fun()。 endl;Fun();catch( int ) cout 在主函数catch子句捕获到整型异常, ;cout 并进行异常处理。 endl;cout 程序结束! endl;return 0;,异常
6、类的层次结构,#include #include using namespace std;class Excp /声明异常基类 public:static void print( string msg )/ 打印错误信息 coutmsgn;Stack myStack(n);cout n;for ( i = 1; i n;for ( i = 1; i = n; count=i+ ) int x;myStack.pop( x );cout 已出栈count个元素!n;,catch(pushOnFull e) e.print(栈已满!);cout 栈中有count-1个元素,;cout值为e.get
7、TempValue()的元素没有压入栈n;catch(newError) newError:print(给栈分配空间时出错!); catch(popOnEmpty) cout 已出栈count个元素,;popOnEmpty:print(栈已空!);catch(Excp) Excp:print(程序其它异常在此处理!); return 0;,标准异常,C+标准库提供的标准异常类的层次结构,标准异常,标准异常的根是exception类 ,其声明如下:namespace std /exception 类在命名空间std 中class exception public:exception() thro
8、w();/缺省构造函数exception( const exception ,标准异常的使用#include/标准异常的头文件#include#includeusing namespace std;class Array public:Array(const char *source, int sz) size = sz; ca = new charsize; for ( int i = 0; i size; +i )if ( !source ) cai = 0;else cai = sourcei;,char ,int main() try char ca = A,B,C,D,E,F; Ar
9、ray CA( ca, sizeof(ca)/sizeof(char) ); CA5=X;/正常访问字符数组类 CA6=G;/越界访问数组类将引发异常 return 0;catch ( const out_of_range ,使用异常处理应注意的几个问题,在C+的程序设计中,异常处理应主要用于独立开发的程序模块之间的异常通信。异常处理机制的使用会影响程序的执行效率。因此,即使C+支持异常处理,在程序设计时也应该具体情况具体分析。在设计一个模块时,如果该模块发生异常时遇到下列情况,则考虑使用异常处理机制:该模块本身不知道如何处理发生的异常,而将由其上级模块负责对异常的判断,并选择采取适当的行动。
10、该模块必须自己处理异常理问题,或者如果它不能完全处理则必须把异常情况“告诉”给使用该模块的上级模块,由其上级模块进行处理。,使用异常处理应注意的几个问题,使用标准异常和异常接口声明在创建自定义的异常类型前,应检查标准C+异常库。如果标准异常正合所需,就拿来为我所用,这样会使我们的程序更易于理解和使用。如果标准异常不能满足要求,则尽量从某个标准异常中派生新增加的异常类型。异常接口声明像一个函数原型:它完整列举了函数可能抛出的所有异常。异常接口声明是函数及其调用者间契约的一部分。换句话说,函数承诺不抛出其它任何不在异常接口声明中的异常。在函数设计时声明异常接口,即便于用户了解函数的异常类型,又能给编译器提供该函数的抛出异常的种类,让编译器“监督”函数是否按照其声明抛出异常。,使用异常处理应注意的几个问题,不要将异常处理当成程序控制结构来使用异常的抛出和捕获有点像函数的调用与返回,而try-catch结构看上去像switch语句。如果在程序中把异常处理当成程序控制流程的手段,可能会带来程序的混乱和执行的低效率。尽量避免在构造和析构函数中抛出异常,本章小结,程序中潜在的异常问题异常处理机制C+中的异常处理标准异常使用异常处理应注意的几个问题,