版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
第7章名字空间与异常处理7.1模块与接口的基本概念7.2名字空间7.3异常处理7.4综合示例小结练习题
7.1模块与接口的基本概念
任何一个设计、构造良好的实用程序均是由若干模块(Module)/构件(Component)组成的,即使它是一个相对简单的程序。这意味着:
(1)可以将程序划分成一组部件。
(2)程序模块的划分可以从多个角度来进行:一是按自己写的程序与它所调用的系统支撑功能(如标准库函数或类库)来划分;二是将自己写的程序本身按某种原则(例如按功能)来进行划分,等等。
程序划分是有目的的。将程序划分成模块,不仅能使其程序结构更加清晰,而且其模块更易于被替换与重用。
C++的名字空间(Namespace)和异常处理机制(ExceptionHanding)就是支持程序模块化组织的强有力机制。
本章我们首先以小型桌面计算器为例,来具体阐述C++用于支持模块化程序设计范型的主要机制——名字空间及相关问题。
逻辑上,我们可将小型桌面计算器按功能划分为以下五大模块。
(1)语法分析器(Parser):完成语言的语法分析;
(2)词法分析器(Lexer):完成语言的词法分析;
(3)符号表(SymbolTable):存储用户标识符的名-值对;
(4)驱动程序(Driver):main函数;
(5)错误处理器(ErrorHandler):进行程序的错误处理。
其中,语法分析器、词法分析器和符号表是该程序的三大核心部件。
程序中各模块之间的划分及模块间的相互关系如图7.1和图7.2所示。图中的箭头表示模块之间的调用关系。
通过前面的学习我们已经知道,仅需了解一个函数接口的具体定义,而无需了解函数的具体实现,我们就能够很好地使用函数。图7.1桌面计算器的程序逻辑划分图7.2桌面计算器的模块关系图类似地,即使程序的一个部件是由多个函数组成的,或者其中既有自定义类型也有全局变量、还有函数,我们都可以这样来设想:如果这样的部件也像函数那样有一个起包装作用的接口,也同样可以只需要了解接口而不需要了解实现,就能够很好地使用它,这正是信息隐藏原理的实质与宗旨。
以此理念,图7.2中程序各模块之间调用的依赖关系我们可用图7.3描述。图7.3程序各模块调用依赖图图7.3中各个模块均调用错误处理模块,考虑图的清晰性,各模块对错误处理模块接口的调用我们暂未画出。
从图7.3可看出,各模块调用时直接依赖的仅仅是所调用模块的接口,而与其调用的实现无关。
确切地说,若程序中的一个部件具有明确的边界,能够实现接口与实现的分离,并对它的用户而言在使用时只需关心其接口而不管其实现,该部件就叫做模块(Module)。
实现模块的接口与实现的分离,需要程序设计语言提供相应的支持机制。C++提供的支持机制是Namespace和Class。
模块用接口隐蔽了其中的数据和函数的处理细节(这也称做封装,Encapsulation),使得模块可以在保持接口不变的前提下,可改变其数据结构和函数的处理细节。
7.2名字空间
7.2.1名字空间的基本概念
C++中的名字空间(Namespace)是一种表现逻辑聚集关系的机制。换句话说,如果一些声明(定义声明与非定义声明)在逻辑上都与某个划分准则有关,就可以把这些声明放入一个共同的名字空间中,以表现这一事实。
同一名字空间中的声明在概念上属于同一个逻辑实体。由于程序中的模块就属于这种逻辑实体,因而我们可用C++的名字空间来封装模块,将程序进行模块化组织。
C++的名字空间的语法形式为
namespace名字空间名
{
//逻辑相关的数据、函数、类或其它等
}
//注意:无“;”号
参照图7.1和第6章桌面计算器的代码,若以模块化的组织形式重构桌面计算器,则其语法分析(parser)模块为
namespaceParser
{
doubleexpr(bool);//非定义声明
doubleprim(boolget){/*…*/}上面,我们仅仅是把一些逻辑相关的部分组织到一个名字空间中(模块),并未实现模块接口与其实现的分离。如何实现这种接口与实现的分离呢?关键是在其模块实现部分中出现的成员被该名字空间的名字所约束(Qualified),这样的约束通过约束符(Qualifier::,C++的作用域解析符)来表示。以桌面计算器的Parser模块为例,进行界面/接口与实现分离的程序代码如下:从上述代码可看出,接口与实现分离的要点是在每个模块接口中仅需非定义声明其中成员的接口部分,其模块成员的实现(如数据、类的定义、函数的定义等)均应以
名字空间名::成员
{
//…
}
的形式进行名字空间外的定义声明。C++语法规定,利用此形式只能进行名字空间内成员的定义声明,而不能利用此语法新定义声明一个名字空间成员。7.2.2名字空间中的名字解析
名字空间既是一个封装体,也是一种作用域。一个名字空间中的名字(符号名)只能在其所定义的名字空间中可见、可用。
名字空间的另一主要用途是将不同的符号名组织到不同的名字空间中,以避免名字冲突。
名字冲突在大型软件的开发过程中是一个突出问题。为了避免这个问题,在C++软件开发过程中,我们应有效地利用名字空间机制对软件中的名字进行有效的组织与管理。例如,开发中,我们可将自己的代码组织到一个命名的名字空间中,以避免和系统类库、其他程序员编制的程序中的名字发生冲突。在以上两个名字空间mfc和owl中,虽然都有同名的变量名inflag,但由于它们属于不同的名字空间,因此不产生名字冲突。
在另一个名字空间中解析其他名字空间的名字,可采取
名字空间名::名字
的方式进行。例如:
mfc::inflag=3; //mfc中的inflag
owl::inflag=-256; //owl中的infalg
当一个应用程序中有多个模块(或名字空间)时,由于各个namespace之间经常会出现互相使用对方成员的情况,如果每次使用就需用名字空间名进行约束,将会导致程序书写既繁琐又容易出错。例如,在Parser模块的term实现中,就用了一系列的名字解析(约束):为了避免这种繁琐易错的名字解析,C++提供了几种“有限的统一”约束机制。
1.using声明语句
语法:using名字空间名::名字;
语义:将某一名字空间中的名字引入(Introduce)到一个局部范围内,使其名字在该范围内无需名字空间的约束便可见、可用。
例如,在Parser模块中,由于使用了若干using声明语句,则在其namespace中我们就可直接采用其他namespace的名字。示例代码如下:需要注意的是,若using声明语句处于某一namespace的界面/接口中,则其using声明语句有效于(作用于)该namespace的所有实现。例如,若我们在Parser名字空间中采用了如下所示的using声明语句:则在parser模块中的所有实现(prim、term和expr)中,get_token、curr_tok和error无需名字空间名约束便直接可见。我们还是以上述的prim实现为例:我们可看出,在上述代码中所出现的其他namespace中的名字一律无需约束(解析),便能直接采用。
2.using指令语句
语法:usingnamespace名字空间名;
语义:将特定名字空间中的所有名字引入到一作用域内。
我们已在前面各章节的示例程序中,多处见到了usingnamespacestd;语句。该语句的功用即将系统std名字空间的所有名字引入(展现)到程序中。
值得注意的是,在一个namespace接口中使用using指令语句,其作用域为其namespace的所有实现中;若using指令语句用于某一个namespace的实现中,则其作用域为该实现内。若我们在namespace的Parser中采用了如下using指令语句:
namespaceParser{
doubleprim(bool);
doubleterm(bool);
doubleexpr(bool);
usingnamespaceLexer; //using指令语句
usingnamespaceError; //using指令语句
}
仍以Parser::prim为例,则在prim中出现的所有Lexer、Error模块中的名字均无需其名字空间名的约束而直接呈现(显露)给prim。请看其代码:实际应用中,是采用using声明语句只将声明的名字引入另一区域,还是用using指令语句将其名字空间中的所有名字引入到另一区域,应具体情况具体分析。
需要切记的是:C++中的namespace是一个范围。采用namespace,我们可以对程序进行逻辑上的组织与划分,程序越大,namespace的功能将愈强。
理想情况下,一个名字空间应该具有以下特性:
(1)是一个描述了具有逻辑统一性特征的相关成员的集合;
(2)实现了接口与实现的分离,对用户隐藏了namespace中的细节;
(3)采用恰当的using声明语句或using指令语句,让用户免去任何明显的名字描述负担。7.2.3模块的多重接口
采用C++的名字空间机制,我们可将程序以模块化的形式组织起来。每一个模块应向调用者只暴露接口,而隐藏其实现。
一个模块通常有不同类别的用户。对不同的用户而言,一个模块应向他们提供不同的接口。例如,某模块的开发者能够涉及模块的全部成员,而这个模块的普通用户则只应当涉及对应于对外功能的那些成员。因此,如果能够为不同的用户提供不同的接口,则该程序既友好又容易控制。又由于面向开发者的接口变动的可能性通常会比面向普通用户的接口更大,从这个意义上来讲,为他们提供不同的接口,有利于隔离内部变动对外界的影响。因此,软件开发中,一个模块应为不同的用户提供不同的模块接口。
我们仍以桌面计算器为例来说明此问题。参看7.1节的图7.1,对于Parser模块而言,面对开发者,我们应提供该模块内所有成员的接口,而对于Driver模块而言,则只需提供Parser模块中的expr函数的接口即可,因Driver只需看到expr的接口。
C++语法上允许为一个名字空间定义多个同空间名的接口。例如,对桌面计算器的Parser模块而言,为Driver可定义如下接口:
namespaceParser
{
doubleexpr(bool);
}
对Parser的实现者(开发者)而言,亦可定义如下同空间名的接口:
namespaceParser
{
doubleprim(bool);
doubleterm(bool);
doubleexpr(bool);
usingLexer::get_token; //using声明语句
usingLexer::curr_tok; //using声明语句
usingError::error; //using声明语句
}但实际的软件开发中,若需要一个模块向外提供多个接口,最好的实现方法是为每一个接口起一个namespace名,实际上采用这种实现方法,可以减少不必要的依赖和名字冲突。因此,就上述问题而言,为Driver和Parser的开发者所提供的两个接口定义分别如下:
namespaceParser_interface //Driver的接口
{
doubleexpr(bool);
}
C++的名字空间机制还有一些相对复杂、高级的用法,在此我们不作赘述,有兴趣的读者可参阅C++标准和相关书籍。
7.3异常处理
对于一个实用的程序而言,没有错误处理是不可能的。实际的(大型)程序是由许多人在不同的时间内开发出来的,许多出错处理任务并不一定能在(或者不应当在)发现出错的地方完成。例如:
intgrandchild(inti)
{
//…
if(出错了)
returnerror_no; //不知如何处理,返回错误号上述函数调用中多处出现了函数出错后对其错误不知如何(或不能够)处理的问题。
一个欠缺良好结构的程序(有时也可能是由于没有语言支持机制造成的),对其错误通常采用判断语句(如C++中的if和switch语句)进行判断与处理。这种判断处理方式带来两个问题:
(1)大量的错误处理代码与程序的功能代码交织在一起,这不仅造成了程序结构的混乱,而且往往错误处理代码远大于程序的功能代码。这使程序不仅很难进行正确的错误处理,而且程序更难以维护与修改。
(2)对于某些错误而言,程序不知如何处理或不能够处理,因而对此类错误只能丢弃,这又往往使程序的可靠性大大下降,甚至在某些极端的情况下,程序退化成不可用。
欲正确处理一个错误,亦称其为异常处理(ExceptionHandling),需要明确知道如下两类信息:
(1)错误发生的地点,何种类型的错误。
(2)怎样处理错误,在何处处理错误。
因此,出错处理任务应当被分解成两部分:错误处理与错误的报告。
(1)在某处(更一般地说是在某一模块)若发现错误(该错误可能是本模块中的错误,亦可能是来自其它模块中的错误),能处理,则进行处理。
(2)不能处理,则应设置出错报告的条件,当满足条件时进行报告,以提供必要的信息,供可能进行错误处理的模块进行错误处理。
C++用try-catch块进行异常处理,用throw语句进行错误的报告。
由于C++异常处理涉及类和类的层次等概念,故C++的详细异常处理机制我们放在第二部分第13章讲述。下面我们仅给出一进行异常处理的程序示例。
7.4综合示例
C++的名字空间和异常处理机制是支持模块化程序设计范型最重要的机制。一个设计良好的软
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 多肽药物生产设备选型与配置方案
- 压铸生产企业人才培训与发展方案
- 燃气计量与收费系统优化方案
- 建筑垃圾消纳场节能减排措施方案
- 数据中心冷却技术优化方案
- 厨余垃圾无害化处理设施建设方案
- 天然气管道施工人员培训与管理方案
- 风电场安全生产管理方案
- 高管薪酬与激励方案设计CEO专项
- 老年心理健康指导师中级绩效考核方案
- 2025年小学五年级语文上学期期中综合测试试卷(含答案)
- 2025年脉石英行业分析报告及未来发展趋势预测
- 2025年建筑师资格考试《建筑装饰设计》备考题库及答案解析
- 2025年政治理论时政热点知识试题库(+答案)
- 贵州金融控股集团有限责任公司招聘笔试题库及答案2025
- 简单版公司向个人借款合同范本5篇
- 《JavaScript程序设计案例教程》全套教学课件
- 2025年铆工中级职业技能理论知识考试练习题库含答案
- 开设国际班申请书
- 2025-2030中国抗心衰药物市场现状及竞争格局分析报告
- 物流发货人员安全培训课件
评论
0/150
提交评论