




已阅读5页,还剩34页未读, 继续免费阅读
版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
C+程序设计,第11章 命名空间与异常处理,1、命名空间 2、异常处理 3、模板,主要内容,一、 命名空间,定义: 是一种将程序库名称封装起来的方法,它就像在各个程序库中立起一道道围墙。比如Windows中,同一目录下不能有两个相同名称的文件,但如果把这两个文件分别放在不同的目录下,就不会存在同名文件的冲突问题。 例如:C:windowstest.txt 和 C:mydatatest.txt 其中前者在C:windows目录下,后者在C:mydata目录下,这些目录就相当于命名空间,它们将同名的文件隔离在不同的目录范围内,从而避免了同名文件的冲突问题。同样道理,假如当前目录是C:windows,使用该目录下的test.txt不必指明目录名,但要使用C:mydata下的test.txt,就必须使用目录名C:mydata。理解这些对后面命名空间的使用非常有益。,namespace 命名空间名 /有名的命名空间 namespace /无名的命名空间 ,命名空间的形式,在两个头文件中分别定义一个有名字的命名空间,其中各有一个类String,但它分属不同的命名空间,即分别变成了one:String()以two:String()。这样,就可以通过声明命名空间来区分不同的类或函数等等了。,【例11.1】有名的命名空间的简单定义,/ two.h namespace two class String . ; ,/ one.h namespace one char func(char); class String . ; ,namespace Outer /命名空间Outer的定义 int i; / Outer的成员i在内部定义 namespace Inner / 子命名空间Inner的内部定义 void f() i+; / Inner的成员f()的内部定义,其中的i为Outer:i int i; void g() i+; / Inner的成员g()的内部定义,其中的i为Inner:i void h(); / Inner的成员h()的声明 / Inner定义的结尾 void f(); / 命名空间Outer的成员f()的声明 / Outer定义的结尾 void Outer:f() i-; / 命名空间Outer的成员f()的外部定义 void Outer:Inner:h() i-; / 命名空间Inner的成员h()的外部定义,【例11.2】命名空间的成员在外部定义,【例11.3】无名命名空间的定义,namespace /注意是无名命名空间! int i; void f() /*/ int main() i = 0; /可直接使用无名命名空间中的成员i f(); /可直接使用无名命名空间中的成员f() 由于命名空间没有名字,在其它文件中自然就没法使用,它只在本文件的作用域内有效。,【例11.4】命名空间的引用,对命名空间中成员的引用,需要使用命名空间的作用域限定运算符:,/ out1.cpp #include “out.h“ #include int main ( ) Outer:i = 0; Outer:f(); / Outer:i = -1; Outer:Inner:f(); / Outer:i = 0; Outer:Inner:i = 0; Outer:Inner:g(); / Inner:i = 1; Outer:Inner:h(); / Inner:i = 0; std:cout “Hello, World!“ std:endl; std:cout “Outer:i = “ Outer:i “, Inner:i = “ Outer:Inner:i std:endl; ,命名空间的使用规则,在本例中,有一个标识符std,即标准库的意思。标准C+库(不包括标准C库)中所包含的所有内容(包括符号常量、变量、结构、类和函数等)都被定义在命名空间std(standard)中 。,1、对偶尔使用的命名空间成员,一般使用命名空间的作用域限定运算符(:)来直接给名称定位。 2、对一个大命名空间中的经常要使用的少数几个成员,提倡使用using声明,而不应该使用using编译指令。 3、对需要反复使用同一个命名空间的许多数成员时,使用using编译指令,才被认为是可取的。,如果要使用C标准程序库的任何标识符时,可以有三种方式: 1)直接指定标识符 std:cout std:hex 3.4 std:endl; 2)使用using关键字 using std:cout; using std:endl; cout std:hex 3.4 endl; 3)使用using namespace std std内定义的所有标识符都有效、可见,就好像它们被声明为全局变量一样。,命名空间的使用规则,命名空间的别名,标准C+引入命名空间,主要是为了避免成员的名称冲突。如果用户都给自己的命名空间取简短的名称,那么这些(往往同是全局级的)命名空间本身,也可能发生名称冲突。如果为了避免冲突,而为命名空间取很长的名称,则使用起来就会不方便。所以C+中提供了一种为命名空间取别名的方式来解决上述两难问题。 格式为: namespace 别名 = 命名空间名;,【例11.5】命名空间别名的使用,namespace East_China_JiaoTong_University / 命名空间名太长 class String String(const char*); / East_China_JiaoTong_University:String s1 /虽易记但不方便! = new East_China_JiaoTong_University:String(““); namespace ECJTU =East_China_JiaoTong_University; / 取别名 ECJTU:String s2 = new ECJTU:String(“Beijing“); / 使用方便,C与C+的头文件的引用方式,在C+的程序代码开头部分,我们经常看到两种写法: 第一种: #include 第二种: #include using namespace std; 这是使用了两种包含头文件的方法。在程序中如果要使用某个函数,就必须在程序形状部分包含相应的头文件。,在C+中使用头文件的两种方法: 1)C语言的方式 头文件名包含.h后缀。由于C语言没有命名空间,所以在编程时如果要用包含.h的头文件时,不必用命名空间。 2)C+的方式 标准C+要求系统提供的头文件不包含后缀.h。但C+从C语言继承了很多有用的函数,且兼容C语言,为了表示它与C语言的联系与区别,C+的头文件名是在C语言的相应头文件名(不含.h)前加上c。 如C中的math.h,在C+中应该为cmath,C与C+的头文件的引用方式,二、异常处理,程序在运行过程中由于使用环境的变化以及用户的操作而产生的错误,称为异常。 对这些错误,应用程序如果不能进行合适的处理,将会使程序变得非常脆弱,甚至不可使用。因此,对于这些可以预料的错误,在程序设计时,应编制相应的预防代码或处理代码,以便防止异常发生后造成严重后果。一个应用程序,既要保证其正确性,还应有容错能力,在C+中,提供了一种异常处理的机制与一套方法。,异常处理的基本思想,在底层发生的问题,逐级上报,直到有能力可以处理异常的那级为止。即在应用程序中,若某个函数发现了错误并引发异常,这个函数就将该异常向上级调用者传递,请求调用者捕获该异常并处理该错误。如果调用者不能处理该错误,就继续向上级调用者传递,直到异常被捕获错误被处理为止。如果程序最终没有相应的代码处理该异常,那么该异常最后被C+系统所接受,C+系统就简单地终止程序运行。如下: func1()func2()func3()func4() 异常处理 引发异常 所以说,C+异常处理的目的,是在异常发生时,尽可能地减少破坏,周密地处理善后,而不去影响程序其他部分的运行。,异常处理的过程,把可能会产生异常的语句或语句块放在try语句块中。程序尝试运行这些语句,一旦它们在运行中产生了异常,那么程序不会被终止,而是转入异常处理程序,根据我们的意愿继续运行下去。,1) 定义异常(try语句),try ,2) 抓住异常(catch语句),将异常处理的语句放在catch语句块中,以便异常被传递来时处理。通常,异常处理是放在try语句块后的由若干个catch语句组成的程序块中,且每个try语句后面必须至少有一个catch语句。,异常处理的过程,catch(异常类型声明1) catch(异常类型声明2) catch(异常类型声明n) 异常处理语句块n ,如果在try语句块中发现了异常,且抛出了该异常,则这个异常就可以被某个catch语句所捕获并处理,捕获和处理的条件是被抛出的异常类型与catch语句的异常类型相匹配。由于C+使用数据类型来区分不同的异常,因此在判断异常时,throw语句中的表达式的值就没有实际意义,而表达式的类型就特别重要。,异常处理的过程,3) 抛出异常(throw语句),C+中的异常是通过throw语句来抛出的。它检测是否产生异常,若是,则抛出异常。,throw 表达式;,【例11.6】异常处理的简单应用,#include using namespace std; void init(int *array,int size); int main() int *p=new int10*1024*1024; int *q=new int10*1024*1024; system(“pause“); try init(p,10*1024*1024); init(q,10*1024*1024); ,catch (.) /代表所有类型 cout“程序产生异常!“endl; cout“准备释放内存.“endl; delete q; return 1; cout“准备释放内存.“endl; delete p; delete q; return 0; ,【例11.6】异常处理的简单应用,程序运行结果: 请按任意键继续. . . 程序产生异常! 准备释放内存 功能分析:程序没有崩溃,并且及时提示发生了错误,且“准备释放内存“也出现了,说明堆内存q肯定被安全释放了。我们对异常的处理目的也达到了。,从上述程序看出,异常处理的执行过程: (1)按正常的顺序执行到try语句,然后执行try语句块内的程序段。 (2)若在try语句块执行期间没有发生异常,则catch语句块不被执行。 (3)若在try语句块执行期间或在该语句块直接或间接调用的任何函数中发生了异常,并将异常抛出,则该异常将沿调用链上传,直到找到与该异常类型相匹配的catch语句块来处理异常。异常处理后,执行所有catch语句块的后续程序。 (4) 如果未找到与该异常类型相匹配的catch语句块,则由C+终止程序的运行。,【例11.6】异常处理的简单应用,补充:,(1)C+只处理放在try语句块内受监控的过程的异常。 (2)在try语句块之后必须紧跟一个或多个catch语句块,以便对发生的异常进行处理。在try语句块出现之前,不能出现catch语句块。 (3)catch语句的括号中只能有一个形参(可选),而形参的数据类型不能缺省必须保留,因为捕获是利用数据类型的匹配实现的。 (4)抛出异常与处理异常可以放在不同的函数中。 (5)catch()语句可以捕获全部异常,因此,若使用这个语句,应将它放置在所有的catch语句之后。 ( 6 ) 为增强程序可读性,C+允许在函数的声明中注明函数可能抛弃的异常类型。语法格式: 返回值类型 函数名(形参列表)throw(异常类型1,异常类2,),三、模板,模板是C+中的一个重要特性,使程序员能够快速建立具有类型安全的类库集合和函数集合,有利于在中型软件的开发。而根据使用的方式不同,又分为函数模板(function template)与类模板(class template)两种。 一般来说,如果一个程序的功能是对某种特定的数据类型进行处理,则将所处理的数据类型说明为参数,就可把这个程序改写为模板,模板可以让程序对任何其它数据类型进行同样方式的处理。因此模板是实现代码复用的一种工具,它可以实现类型参数化,把类型定义为参数,实现代码的真正复用。,函数模板和模板函数,函数模板首先是模板而非函数,它是各相似函数的抽象,当然具有函数的形式。 模板函数则是由模板实例化后产生的具体函数。这好比工厂要生产一个茶杯,产生要根据茶杯的大致要求制造出一个模具(函数模板),之后用该模具再去批量生产茶杯(模板函数)一样。,函数模板的声明形式为: template (参数表) 函数体 其中,template是定义模板函数的关键字;typename是声明数据类型参数标识符的关键字,用以说明它后面的标识符是数据类型标识符(注:typename是新引入的关键字,此前一直用class,有些老版本的编译器可能不识别typename,此时宜改成class)。这样,在以后定义的这个函数中,凡希望根据实参数据类型来确定数据类型的变量,都可以用数据类型参数标识符来说明,从而使这个变量可以适应不同的数据类型。,函数模板的声明,【例11.7】简单函数模板的应用,#include using namespace std; template T sum(T x, T y) return x+y; int main() int ia=4,ib=5,isum; float fa=4.1,fb=5.5,fsum; double da=4.12345,db=5.12345,dsum;,isum=sum(ia,ib); fsum=sum(fa,fb); dsum=sum(da,db); cout“int_sum=“isumendl; cout“float_sum=“fsumendl; cout“double_sum=“dsumendl; return 0; ,运行结果: int_sum=9 float_sum=9.6 double_sum=9.2469,【例11.7】简单函数模板的应用,功能分析: 在调用sum函数时编译器将根据数据参数的类型依照函数模板生成一个重载函数,再调用它。 比如:isum=sum(ia,ib);其中ia、ib是int型,函数模板会把“虚拟“参数T用int代替,从而生成一个具体的模板函数int sum(int x,int y)(即由模板生成的函数): int sum(int x,int y) return x+y; 程序再调用此函数得到结果为9,赋值给isum。,函数模板小结:,函数模板只是声明了一个函数的描述即模板,不是一个可以直接执行的函数,只有根据实际情况用实参的数据类型代替类型参数标识符之后,才能产生真正的函数。 使用中应注意的几个问题: (1)函数模板允许使用多个类型参数,格式为: template (参数表) 函数体 ,函数模板小结:,(2)在template语句与函数模板定义语句之间不允许有别的语句。 template int x; /这样声明是错误的! T min(T x,T y) 函数体 (3)模板函数类似于重载函数,但两者有很大不:函数重载时,每个函数体内可以执行不同的操作,但同一个函数模板实例化后的模板函数都必须执行相同的操作。,类模板与模板类,数据的类型各种各样,为了能让类适应各种类型,此时设计类时也可以象函数模板一样,定义一个与具体类型无关的类,这就是类模板。类模板可以为类定义一种模式,使得类中的某些数据成员、某些成员函数的参数或返回值可以取任意的数据类型。 类模板不是一个具体的类,是类的抽象类型,代表一族类,是这一族类的统一模式, 类模板是一个类型参数化的样板,它是一组模板类的集合,模板类是某个类模板的实例,使用某种类型来替换某个类模板的模板参数可生成该类的一个模板类。,template class 类名 类体 ; 其中,template是声明类模板的关键字;数据类型参数标识符是类模板中参数化的类型名,当实例化类模板时,它将由一个具体的类型来代替。 同样,定义类模板时,可以声明多个类型参数标识符,各标识符之间用逗号分开。,类模板的形式,类定义中,凡要采用标准数据类型的数据成员、成员函数的参数或返回类型的前面都要加上类型标识符。如果类中的成员函数要在类的声明之外定义,则它必须是模板函数。形式为: template 参数标识符 类名函数名 (标识符 形参1,标识符 形参n) 函数体 ,类模板的形式,定义类模板时应注意如下几点: (1) 定义类模板时使用关键字template。 (2)定义类模板时至少要确定一个模板参数,多个模板参数用逗号分隔。 (3)类模板的成员函数可以是函数模板。在类体外定义函数模板时,应在模板名前用类模板名限定()来表示该函数模板的所属。,类模板的形式,【例11.8】类模板的应用,#include const int size=10; template /定义类模板 class stack T stksize; int t; public: stack() t=0; int push(T ch); /类模板的成员函数声明 T pop(); ;,【例11.8】类模板的应用,/当类模板中的成员
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 2025年教师招聘之《幼儿教师招聘》通关练习试题附参考答案详解【考试直接用】
- 空间分析考试题及答案
- 客服转正考试题及答案
- 炼钢工内部技能考核试卷及答案
- 燃气储运工技术考核试卷及答案
- 铝电解筑炉工岗位操作技能考核试卷及答案
- 铝电解工质量追溯知识考核试卷及答案
- 拖拉机燃油喷射系统装试工抗压考核试卷及答案
- 球团原料工标准化作业考核试卷及答案
- 固体废物监测员职业技能考核试卷及答案
- 手术室专科护士职业考试试卷与答案
- 业余少体校管理办法
- 天津校外培训管理办法
- 小学生晨会课件
- 依法治校视角下高校后勤管理法律风险的识别与化解策略
- 2025至2030锆英砂行业市场发展分析及发展趋势与投资报告
- DB44∕T 2499-2024 海堤生态化建设技术导则
- 地质灾害诱因成因分析方法-洞察阐释
- 护林防火培训
- 大小便失禁护理指南
- 物业弱电维修课件
评论
0/150
提交评论