180 likes | 333 Views
面向对象程序设计. 1. 异常处理. 教学内容 § 异常的概念 § 错误处理的复杂性 § 异常机制 § 异常处理中的构造与析构 § 异常与继承. 在大型软件开发中 , 最大的问题就是错误与不稳定代码 , 而在设计一实现中 , 最大的开销是花在测试 , 查找和修改错误 . 程序的错误 , 一种是编译错误 , 即语法错误 . 这种错误通常不能生成运行代码 . 另一种错误是在运行时发生的错误 , 它分为不可预料的 逻辑错误 和可以预料的 运行异常. § 异常的概念.
E N D
面向对象程序设计 1
异常处理 教学内容 §异常的概念 §错误处理的复杂性 §异常机制 §异常处理中的构造与析构 §异常与继承
在大型软件开发中,最大的问题就是错误与不稳定代码,而在设计一实现中,最大的开销是花在测试,查找和修改错误.在大型软件开发中,最大的问题就是错误与不稳定代码,而在设计一实现中,最大的开销是花在测试,查找和修改错误. 程序的错误,一种是编译错误,即语法错误.这种错误通常不能生成运行代码.另一种错误是在运行时发生的错误,它分为不可预料的逻辑错误和可以预料的运行异常. §异常的概念
逻辑错误是由于设计不当造成的,如某个排序算法不合适,导致在边界条件下,不能正常完成排序任务. 一般只有当用户做了某些出乎意料的事才会出现逻辑错误.这些错误安静地潜伏着,就象大战之后残的地雷,当进入雷区可能发生爆炸. • 运行异常可以预料,但不能避免,它是由系统运行环境造成的.如内存不足,打印机未打开,等,这些错误是能够预料的,可通过加入一些预防代码以防止这些异常.
§错误处理的复杂性 传统的错误处理方式: • 遇到错误,终止运行,低级粗暴 //------------------------------------- void fn(){ ifstream in("abc.txt"); if(!in) { cout<<"Error: open file failure.\n"; exit(1); } for(int a; in>>a; cout<<sqrt(a*1.0)<<"\n") if(a<0) { cout<<"Error: read in illegle data.\n"; exit(1); } }//------------------------------------ int main(){ fn(); } //=====================================
§异常机制 • 异常是一段代码遇到异常状态后,通知另一段代码(异常处理代码)并进行处置的机制。 • 遇到错误的代码抛出(throw)异常 • 处理异常的代码捕获(catch)异常 • 异常的处理流程不遵守常规的代码执行流程,代码抛出异常后,立即停止执行,跳转到异常处理处。 -6-
异常处理的实现机制 • 捕获并处理异常的程序段 try{ 被检查语句 } catch(异常类型声明){ 进行异常处理语句} catch(异常类型声明){ 进行异常处理语句} … 注:catch代码块必须出现在 try块之后 • 抛掷异常的程序段 ...... throw 异常类的对象; ...... 抛出的对象可以是包括系统预定义类型在内的任何类型,当然多数情况为自定义异常类型,
运行结果: 5/2=2 except of deviding zero. that is ok. int Div(int x,int y); int main() { try { cout<<"5/2="<<Div(5,2)<<endl; cout<<"8/0="<<Div(8,0)<<endl; cout<<"7/1="<<Div(7,1)<<endl; } catch(int) { cout<<"except of deviding zero.\n"; } cout<<"that is ok.\n"; } int Div(int x,int y) { if(y==0) throw y; return x/y; }
流程控制规则: • 1)如果没有异常发生,继续执行try块中的代码,与try块相关联 的catch子句被忽略, • 2)当某条语句抛出异常时,跟在该语句后面的语句将被跳过。程序执行权交给处理异常的catch子句,如果没有catch子句能够处理异常,则交给C++标准库中定义的terminate()。try块也退出 .
调用者 函数f5()捕获并处理异常 …… 调用关系 异常传播方向 函数f1() 函数f0() 引发异常 异常处理的基本思想 这样可以提高效率 void f0(){ throw string(“请处理\n”); } void f1(){ f0(); } void f2(){ f1(); } void f3(){ f2(); } void f4(){ f3(); } void f5(){ f4(); } int main(){ try{ f5(); } catch(string){ cout<<“处理中\n”; } }
//f1504.cpp------------------------------------- void procFileName(string s); void procOpenMode(string s); void openIn(string s); void openOut(string s); //------------------------------------- int main(){ procFileName("iabc"); procFileName("oabc"); }//------------------------------------ void procFileName(string s){ try{ for(char c='0'; c<='9'; c++) procOpenMode(s + c+".txt"); }catch(string s){ cout<<"error opening "<<s<<" not existed.\n"; } }//------------------------------------
void procOpenMode(string s){ if(s[0]=='i') openIn(s); else openOut(s); }//------------------------------------ void openIn(string s){ ifstream in(s.c_str()); if(!in) throws+" inFile"; for(string line; getline(in, line); cout<<line<<"\n"); }//------------------------------------ void openOut(string s){ fstream out(s.c_str(),ios::in|ios::out|ios::ate); if(!out) throws+string(" outFile"); out<<s+" outFile is ok.\n"; cout<<s+" is here.\n"; }//====================================
§捕捉异常 ( Catching Exception ) 类型匹配 异常捕捉的类型匹配之苛刻程度可以和模板的类型匹配媲美,它不允许相容类型的隐式转换,比如,抛掷char类型用int型就捕捉不到.例如下列代码不会输出“int exception.”,从而也不会输出“That’s ok.” int main(){ try{ throw 'H' }catch(int){ cout<<"int exception.\n"; } cout<<"That's ok.\n"; }
在C++中异常往往用类来实现,如: #include<iostream> using namespace std; class Exception { public: Exception(){} virtual~Exception(){} virtual void PrintError()=0; }; class RangeError:public Exception { int BadNum; public: RangeError(int n){BadNum=n;} ~RangeError(){} virtual void PrintError(){cout<<"Number out of range.You used!" <<BadNum<<endl;} };
int main() { int num; cin>>num; try{ if(num>100||num<0) throw RangeError(num);} catch( Exception& e){ e.PrintError(); } system("pause"); }
§异常处理中的构造与析构 • C++异常处理能力,不仅在于它能够处理不同类型的异常,还在于它具有为异常抛掷前构造的所有局部对象自动调用析构函数的能力。 • 找到一个匹配的catch异常处理后 • 初始化参数。 • 将从对应的try块开始到异常被抛掷处之间构造(且尚未析构)的所有自动对象进行析构。 • 从最后一个catch处理之后开始恢复执行。
#include<iostream> using namespace std; class Exception { public: Exception(){cout<<"基类对象被构造\n";} virtual~Exception(){cout<<"基类对象被析构\n";} virtual void PrintError()=0; }; class RangeError:public Exception { int BadNum; public: RangeError(int n){cout<<"派生类对象被构造\n";BadNum=n;} ~RangeError(){cout<<"派生类对象被析构\n";} virtual void PrintError(){cout<<"Number out of range.You used!" <<BadNum<<endl;} };
int main() { int num; cin>>num; try{ if(num>100||num<0) throw RangeError(num);} catch(Exception& e){ e.PrintError(); } system("pause"); }