版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
1、Object-OrientedProgramming in C+第八章 C+工具,中国科大学继续教育学院 李艺 ,第一章 C+的初步知识 第二章 类和对象 第三章 再论类和对象 第四章 运算符重载 第五章 继承与派生 第六章 多态性与虚函数 第七章 输入输出流 第八章 C+工具 第九章 模板,8.1 异常处理 8.2 命名空间 8.3 使用早期的函数库,8.1 异常处理,概述:程序的错误有两种:一种是编译错误,即语法错误。另一种是在运行时发生的异常(exception) 。 异常处理机制只处理运行时的差错和其它例外情况,不包括编译错误。 处理异常的方法有: 非结构化异常处理:用 exit (n
2、) 或 return (n)的运行期错误处理机制,具有“一个入口,多个出口”的特点。exit()会清空流和关闭打开的文件。abort()却不会清空流,也不关闭打开的文件。 结构化的异常处理:按“警告忽略”、“对话补救”或安全退出等模式,使程序可以在对运行条件做出适当安排或改善后继续运行下去。,8.1 异常处理,基本思想: C+的异常处理的基本思想是将异常的检测与处理分离。 在一个函数体中检测到异常条件满足,但无法确定相应的处理方法时,就引发一个异常,然后由函数的直接或间接调用者处理此异常。 C+的异常处理建立在三个关键字基础之上: try 、catch 和 throw。,8.1 异常处理,C+
3、异常处理语句的一般形式 try /try 块内监视异常 if (条件)throw exception; /由throw 抛出异常 ; /其它语句 catch( 类型1 参数1 ) /catch块内处理代码 catch( 类型2 参数2 ) ; catch( 类型n 参数n ) ; ,注意:C+通过try夺取运行期的环境控制权,即异常的引发是由程序员控制的,而不是由程序运行环境或计算机硬件控制的。任何要检测异常的语句或函数调用都必须在try语句块中执行。异常由紧跟在try块后的catch语句来捕获并处理。,8.1 异常处理,#include #include float Div(float x,
4、float y); void main( ) try float a=1.0,b; while (a0.0) cout a; cout b; couta/b=Div(a,b)endl; catch (float) coutdeviding is zero.nn; coutthat is ok.n; float Div(float x,float y) if (fabs(y)0.0001) throw y; return x/y; ,方框中的代码是没有 异常处理机制的代码,8.1 异常处理,说明 如果预料某段程序代码有可能发生异常,就将它放在try子句的化括号中。如果这段代码运行时真的遇到异常情
5、况,其中的throw表达式就会抛出这个异常。 出现异常时,try语句块提示编译器到哪里查找catch块,没有紧跟try块的catch块是没有作用的。 当没有发生异常的时候,几乎没有和try块相关的运行时成本。查找匹配捕获处理异常的过程只在发生异常的情况下才会进行。,8.1 异常处理,catch子句后的复合语句是异常处理程序。它捕获由throw表达式抛出的异常。 异常类型说明部分指明该子句处理的异常的类型,它与函数的形参是相似的。可以是某个类型的值,也可以是引用。 如果某个catch语句的参数类型与引发异常的信息数据类型相匹配,则执行该catch语句的异常处理(捕获异常),此时,由throw语句
6、抛出的异常信息(值)传递给catch语句中的参数。,8.1 异常处理,try语句块必须出现在前,catch紧跟在后。catch之后的圆括号中必须含有数据类型,捕获是利用数据类型匹配实现的。在try 和catch() 语句之间不得插入任何其它C+语句。 如果程序内有多个异常处理模块,则当异常发生时,系统自动查找与该异常类型相匹配的catch模块,查找次序为catch出现的次序。需要注意的是catch处理程序的出现顺序很重要,因为在一个try块中,异常处理程序是按照它出现的顺序被检查的。,8.1 异常处理,引发异常的throw语句必须在try语句块内,或是由try语句块中直接或间接调用的函数体执行
7、。throw语句的一般形式为: throw exception; exception表示一个异常值,它可以是任意类型的变量、对象或常量。,8.1 异常处理,#include const double PI=3.1416; void invoke(int x) try if(x=0) throw x+5; /抛出int型的异常 if(x=1) throw A; /抛出cahr型的异常 if(x=2) throw An apple; /抛出字符串型的异常 if(x=3) throw PI; /抛出double型的异常 catch(int i) coutcatch a integer iendl;
8、catch(char c) coutcatch a char cendl; catch(char str10) coutcatch a string strendl; catch(double d) coutcatch a double dendl; ,程序运行结果: catch a integer 5 catch a char A catch a string An apple catch a double 3.1416,void main() invoke(0); invoke(1); invoke(2); invoke(3); ,8.1 异常处理,异常的类型匹配规则 C+规定,当一个异常
9、对象和catch子句参数类型符合下列条件时,匹配成功: 如果catch子句参数类型就是异常对象的类型或其引用 如果catch子句参数类型就是异常对象的public基类 如果catch子句参数类型为基类指针或引用,而异常对象为派生类指针或引用。 catch子句参数类型为void*,异常对象为任何类型指针。 catch子句为catch-all,即catch。 catch处理程序按照其在try块后面的顺序依次为检测,一旦匹配,则后面的就不再检测。,8.1 异常处理,异常的匹配规则比函数重载的匹配规则更为严格 try throw int(); catch (unsigned int) 抛出异常的类型是
10、int型,然而handler却期待一个unsigned int。异常处理机制不认为二者是能够匹配的类型;结果,抛出的异常没有被捕获。,8.1 异常处理,异常重抛( re-throw ): 当catch捕获异常后,可能不能完全处理异常,在完成某些操作后,可以重新抛出该异常,把异常传递给上层函数的另一个catch子句,由它进一步处理。重新抛出异常的表达式仍然为:throw;被重新抛出的异常就是原来的异常对象。如: void f( ) try throw 1; catch (int e) /do something; throw ; int main( ) try f(); catch ( int
11、e) cout “exception in main is ” e; return 0; ,8.1 异常处理,#include #include using namespace std; void myFunc( ) try int a; couta) if (a4) throw e; else cout输入的数据 a 合格nn; if (a=1) exit (0); else cout “请输入一个小于5的自然数:; catch (string ,void main( ) try myFunc( ); catch (string ,8.1 异常处理,重抛异常的catch子句应该把自己做过的工
12、作告诉下一个处理异常的catch子句,往往要对异常对象做一定修改,以表达某些信息。 因此catch子句中的异常声明必须被声明为引用,这样修改才能真正做在异常对象自身中,而不是拷贝中。,8.1 异常处理,catch_all子句 通常异常发生后按栈展开(stack unwinding)退出,动态分配的非类对象资源是不会自动释放的,应该在对应的catch子句中释放。因为我们不知道可能被抛出的全部异常,所以不是为每种可能的异常写一个catch子句来释放资源,而是使用通用形式的catch子句catch_all,格式为: catch(.) 代码 ,8.1 异常处理,catch_all子句示例: void
13、fun1( ) int *res; new res100;/定义一个资源对象 try/代码包括使用资源res和某些可能引起异常抛出的操作 catch(.) delete res;/正常退出前释放资源对象res; throw;/重新抛出异常 catch_all子句可以单独使用,也可以与其它catch子句联合使用。但必须放在相关catch子句表的最后。,8.1 异常处理,异常的限制 在异常处理中,由于捕获和抛出一个异常会影响到一个函数与其它函数的相互关系。因此,C+异常机制允许在函数定义后面增加一个抛出类型说明,以限制该函数可以抛出的异常类型。 异常限制的一般格式如下: 返回值类型 函数名() t
14、hrow () . 使用时应特别注意,经这样定义的函数,抛出的异常数据只能是异常类型列表中的一种。,8.1 异常处理,如果一个函数抛出的异常没有在抛出类型列表中说明或者从所列数据类型之一派生,默认的异常处理过程就是调用名为unexpected()的函数,该函数又调用terminate()函数,后者依次再调用abort()函数终止程序运行。其中,对unexpected()和terminate()用户可以提供自己的函数定义。,8.1 异常处理,例12. 3 异常限制演示 (VC+6.无此功能) #include void invoke(int test) throw(int, char) if (
15、test=0) throw test; if (test=1) throw a; if (test=2) throw 123.23; void f(int t) try invoke(t); catch (int j) coutCaught an integer jendl; catch (char c) coutCaught a char: cendl; catch (double d) coutCaught a double dendl; ,void main( ) f(0); f(1); f(2); coutEndendl; ,执行结果如下: Caught an integer 0 Ca
16、ught a char: a Abnormal program terminate,8.1 异常处理,异常成组 将多个有某种关联的异常放在一组。这些异常通常属于某一个方面的异常。比如文件异常组。 在C+异常处理中,有两种方式把多个异常成组。它们是:异常枚举成组和异常派生类成组。,8.1 异常处理(异常枚举成组),#include enum errserr0,err1,err2; void f(int test) try if(test=0) throw err0; if(test=1) throw err1; if(test=2) throw err2; catch(errs er) swit
17、ch(er) case err0: coutCaught err0 exceptionn; break; case err1: coutCaught err1 exceptionn; break; case err2: coutCaught err2 exceptionn; break; void main( ) f (2); f (1); f (0); ,8.1 异常处理,异常和派生类成组 在C+程序中,表示异常的类通常被组成为一个组(group)或者一个层次结构。对由栈类成员函数抛出的异常: class popOnEmpty.; class pushOnFull.; 可以定义一个称为Exc
18、p的基类,再从该基类派生出这两个异常类。 class Excp.; class popOnEmpty:public Excp.; class pushOnFull:public Excp.;,8.1 异常处理,由基类Excp来打印错误信息: class Excp public: void print (string msg) cerr msg endl; ; 这样的基类也可以作为其他异常类的基类: class Excp.; /所有异常类的基类 class stackExcp:public Excp.; /栈异常类的基类 class popOnEmpty:public stackExcp.; /
19、栈空退栈异常 class pushOnFull:public stackExcp.; /栈满压栈异常 class mathExcp:public Excp.; /数学库异常的基类 class zeroOp:public mathExcp.; /数学库零操作异常 class divideByZero:public mathExcp.; /数学库被零除异常,8.1 异常处理,这里被创建的异常类对象是stackExcp类类型,尽管pse指向一个实际类型为pushOnFull的对象,但那是一个临时对象,拷贝到异常对象的存贮区中时创建的却是stackExcp类的异常对象。所以该异常不能被pushOnFu
20、ll类型的catch子句处理。 在处理类类型异常时,catch子句的排列顺序是非常重要的。当异常被组织成类层次结构时,类类型的异常可以被该类类型的公有基类的catch子句捕获到。如pushOnFull类类型的异常可以由stackExcp或Excp类类型异常所对应的catch子句处理。为了保证pushOnFull异常的处理由最合适的catch子句来处理,应有如下顺序: catch (pushOnFull). /处理pushOnFull异常 catch (stackExcp). /处理栈的其他异常 catch (Excp). /处理一般异常 派生类类型的catch子句必须先出现,以确保只有在没有其
21、他catch子句适用时,才会进入基类类型的catch子句。,8.1 异常处理,异常派生类成组示例:对学生信息(姓名、年龄、成绩)进行输入,要求将输入不合理的数据抛出不用。 思路:先定义一个抽象类check;由它派生出三个派生类:nameCheck、ageCheck 和 scoreCheck,来分别检查name、ade、score录入是否合理,如果不合理,则抛出不用。 长处:用派生类成组进行异常处理,其catch字句可以非常精练、易读。,#include #include using namespace std; class check public: virtual void set()=0;
22、 virtual void showErr()=0; virtual void display()=0; protected: string name; int age; int score; ; / 检查抽象类结束,8.1 异常处理,class nameCheck:public check public: void set() coutname; if (isNum(name) throw this; void showErr() cout age; if (age120) throw this; void showErr() cout 年龄输入错误! endl; void display(
23、) cout 学生年龄:ageendl; ; / 年龄检查类结束,class scoreCheck:public check public: void set() coutscore; if (score100) throw this; void showErr() cout set(); pt2 = new ageCheck; pt2 - set(); pt3 = new scoreCheck; pt3 - set(); pt1-display(); pt2-display(); pt3-display(); catch(check *chk) chk-showErr(); return 0
24、; ,8.1 异常处理,类层次结构的异常同样可以重新抛出(rethrow),把一个异常传递给函数调用列表中,更上层的另一个catch子句。形式仍为 throw; 虚函数是类层次结构中多态性的基本手段,异常类层次结构中也可以定义虚拟函数。,8.1 异常处理,例:异常层次结构中的虚函数,#include class Excp public: virtual void print( ) cerr”发生异常” endl; ; class stackExp:public Excp public: virtual void print( ) cerr”栈发生异常”endl; ; class pushOnF
25、ull:public stackExcp public: virtual void print( ) cerr”栈满,不能压栈”endl; ;,int main() try /抛出一个pushOnFulll异常 catch(Excp /调用虚函数 pushOnFull:print() ,8.2 命名空间,本课程的各章节的程序中,都用到了这样的语句: using namespac std; 这就是命名空间std。 为什么需要命名空间?C语言定义了3个作用域,即文件域,函数域和复合语句域。C+又引入了类作用域。 不同的作用域中可以用相同的变量名,互不干扰。但是,如果是在不同的库文件( *.h )中
26、,有相同的变量名和类名,而不巧又在被一个程序包含、主文件中又调用了该变量,定义了该类对象,于是引起矛盾冲突。,8.2 命名空间,什么是命名空间?为了解决这个问题,ANSI C+增加了命名空间的概念。简单地说,就是ANSI C+引入的,可以由用户命名的内存区域,把一些全局实体分别放在各个命名空间中,从而与其他全局实体分隔开来。比如: namespace nsl int a; double b; 其中: namespace 是定义命名空间的关键字; nsl 是用户指定的空间名。 花括号内包含的a,b,是命名空间成员。,8.2 命名空间,注意a 和b 仍然是全局变量,仅仅把它们隐藏在命名空间中,而程
27、序中如果要使用变量a 和b,必须加上空间名和域分辨符。如:nsl:a,nsl:b 等。这些名字称为被限定名。 C+中的命名空间和被限定名的关系,类似与操作系统中文件夹和其中文件的关系。 命名空间的作用:是建立一些互相分隔的作用域,把一些全局实体分割开来,以免产生名字冲突。命名空间中的被限定名可以是: 常量和变量( 可以带有初始化 ); 函数( 可以是定义或声明 ); 结构体或类; 模板或另一个命名空间( 意味着,命名空间可以嵌套 ),8.2 命名空间,使用命名空间解决名字冲突:我们举例说明如何解决冲突。,/ header1.h #include #include using namespace
28、 std; namespace ns1 / 声明命名空间ns1 class student / 在ns1中声明学生类 public: student (int n, string nam, int a) num=n; name=nam; age=a; void get_data( ); private: int num; string name; int age; ; void student:get_data() coutnum“ “name “ageendl; double fun (double a, double b) / 在ns1中定义fun函数 return sqrt(a+b);
29、,/ header2.h #include #include using namespace std; namespace ns2 / 声明命名空间ns2 class student / 在ns1中声明学生类 public: student (int n, string nam, char s ) num=n; name=nam; sex=s; void get_data( ); private: int num; char name20; int age; ; void student:get_data() coutnum“ “name “sexendl; double fun (doubl
30、e a, double b) / 在ns1中定义fun函数 return sqrt(a-b); ,8.2 命名空间,两个头文件中有相同名字的类和函数,分别放在不同的命名空间中,避免冲突。 定义对象时,要使用: 空间明:类名 对象名(参数表) 的形式来定义对象。 定义好的对象不在命名空间中,而在main 函数的范围里,所以使用对象时,不能加空间的名字!,/ main file #include #include “header1.h” #include “header2.h” using namespace std; int main( ) nsl:student stud1(101,”Wang
31、”,18); stud1.get_data( ); / 不要写成ns1:stud1.get_data( ) coutns1:fun(5,3)endl; ns2:student stud2(102,”Li”,f); stud2.get_data( ); coutns2:fun(5,3)endl; return 0; ,8.2 命名空间,使用命名空间的简化形式:如果在一个命名空间中定义了至少10个实体,就需要至少使用10次 using 命名空间名。能否简化呢?可以。 C+提供 using namespace 语句来实现简化。其一般形式为: using namespace 命名空间名; 例如, using namespace ns1; 声明了在本作用域中要用到命名空间ns1 中的成员,在使用该命名空间的任何成员时,都不必使用 ns1 空间名来限定。好象全局对象一样。如果紧接上面的声明,有如下语句: student stud1(101, “Wang”,18); 则是指定义一个ns1空间
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- GA/Z 2328-2025法庭科学资金数据分析标准体系表
- GA 2180-2024警用服饰移民管理警察丝织帽徽
- 2026年陕西省西安交大附中初三下学期质量调研考试(一模)物理试题含解析
- 江苏省无锡市刘潭中学2025-2026学年开学摸底考试初三数学试题含解析
- 2026年大学大一(建筑材料)砂浆强度检测综合测试题及答案
- 防洪预案编制指南
- 2025年前台服务保险箱考核练习卷
- 警惕六大决策“陷阱”
- 护理操作技能
- 护理学基础:病区环境的心理支持作用
- 物业小区控烟监督制度
- 2026年郑州市检验检测有限公司公开招聘19人笔试备考题库及答案解析
- 2026年春季安全教育班会记录表(19周):开学安全第一课-启航安全守护新学期
- 多模式镇痛临床实践与应用
- 2025年黄山职业技术学院单招职业技能测试题库附答案解析
- 2026吉林农业大学三江实验室办公室招聘工作人员笔试备考试题及答案解析
- 脑中风科普知识讲座
- 大坝安全监测仪器检验测试规程
- 绿色数据中心 暨对算力行业的一点思考 行业洞察 2026
- 历史试题-汕头市2025-2026学年度普通高中毕业班教学质量监测(含解析)
- 部队食堂制度规范标准
评论
0/150
提交评论