7第七讲——名空间和RTTI

合集下载
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

命名空间(nຫໍສະໝຸດ Baidumespace)
“命名空间”:为语言再设定一个命名的作用域 (named scope)——又加了一层隔离带,将所用 的标识符集合其内,域外使用时便多了一层名称来 标明归属。“名空间”在UML 中统称为“包”。 声明一个命名空间NS: namspace NS { class File; void Fun (); ... // 所有空间成员的声明必须写在名空间内 }
namespace U{ void f(); void s(); } namespace V{ void f(); //可以有多个f,它们是重载关系 void s(); 将引进重载的所有的f() } void func() { using namespace U; using V::f; // 注意,只写f,不写参数和返回类型 f(); // 必然是V空间的f() U::f(); // 这才是U空间的f() }
void main () { G(); using namespace A; F(); B::F(); B::C::F(); G():from global namespace A::G(); F():from namespace A } F():from namespace B
F():from namespace C
C++语言程序设计
命名空间和RTTI
本章主要内容

命名空间 RTTI的概念 RTTI的两种使用方法 合理使用RTTI
在无“命名空间“的年代
记得在五六十年代,火车站的候车室(还有 候船厅)里都有块“旅客留言板”。人们在上 面留下自己的纸条。“小李,我已乘xx次列车 走了。”、“老王,我已抵连,现住在xx旅 馆。” ... 开始,旅客较少时很方便。但随着 旅客的增多,由于简称、同名等造成的误解, 带来的不是方便,而是混乱。 可见公共资源的是不可滥用的,必须加以限 制。

名空间的性质

“名空间”是跨越文件的。它不是简单的包含了文件, 而是更灵活的超越了文件。是个逻辑概念,就如同活动 在校内外的学生依然从属于某系某班级一样。
名空间的追加定义
namspace A { class File; void Fun (); } namspace A //合并进了A { void Func(); }
include 与 using namespace 的区别和联系: 前者是将某文件搬到本地来,搬来了未必好用,是否 能用全在后者。 using ... 只是告诉编译器,扫描源代码时,凡遇到非 本作用域的标识符该到哪去找。
#include <iostream.h> namspace A { void F () { cout<<“F():from namespace A”<<endl; } void G () { cout<<“G():from namespace A”<<endl; } namspace B { void F () { cout<<“F():from namespace B”<<endl; } namspace C { void F () { cout<<“F():from namespace C”<<endl; } } } } void G () { cout<<“G():from global namespace”<<endl; }
namspace B { class File; void Fun (); namspace C //名空间可以嵌套。 { class File; void Fun (); } }
匿名空间
“匿名空间”:设定一个无名的命名空间,将标识符 集合其内,由于无名,本文件的域外可以无限制地 使用该空间的标识符,省却了定义时的static,使用 时也节省了空间名前缀。但别的文件不可使用。因 此匿名空间的作用相当于C时代的静态全局变量 。 如: namspace { class File; void Fun (); } 匿名空间也可以跨文件追加。 一个编译单元只可有一个匿名空间。

名空间可以指定别名。注意不可使用typedef.
要使用 namespace ANS = NS; namespace American_Telephone_and_Telgraph{} namespace ATT = American_Telephone_and_Telgraph ATT是名空间别名。

然后,在源程序开发时,就可以将这三个模块 文件作为资源使用。当然,要对各头文件中所 涉及的函数予以实现。

名空间尽管发源于模块的划分和隔离,服务于 模块设计的开发模式,但从中受益的不仅是模 块,还有数据的使用。当然数据要求更细致的 服务,名空间就显粗糙了些,更精细的是类。

四个强制转换运算符 RTTI的概念 RTTI的两种使用方法 合理使用RTTI
// file3.h namespace f3 { void h1(); }
// file4.h namespace f4 { void n1(); void n2(); }
k4
k2
文件5
k1 h1 k1
k5
k3
m2
文件6
m1 m1 m1
m3
模块3
// module1.h namespace m1 { #include “file1.h” } //using namespace f1; // module2.h namespace m2 { #include “file2.h” #include “file3.h” } //using namespace f2; //using namespace f3;
2规则的示例: //用using std::声明,访问标准库的标识符 #include <set> #include <iostream> void main() { using std::set<int>::iterator; // 单个永久打开 int a[100] = {10}; std::set<int> iSet(a,a+99); // 每每要打开set iterator it = iSet.find(25); // iterator不用再打开了 std::cout<<" "<<*it<<std::endl; //要每每打开cout }
新增的四个强制类型转换符
“强制”的含义: 在告诉编译器: “我知道你不愿意这样做,可是你必须做。尽管 执行吧,后果由我负责!”
const_cast
对象自身.
static_cast
除去对象的常属性。转换的是表达式而非 形式:const_cast < type > ( object )
3. “全面开放,一劳永逸”
用指示符using:
using namespace std;语句后,名空间std中的所有 标识符都在本作用域中开放,可直接使用。此法将引 起标识符的“全面冲突”。 此法用于使用的名空间标识符个数、次数都很多时。 此法将因别的名空间的引进而产生“名冲突”。编 译器的仲裁准则是“外来服从本层”。它的在外层, 你的在内层,内层屏蔽外层。被屏蔽的同名者可用空 间名::标识符 来区分。 用2方法打开时可能发生的“个别冲突”,也用此 法解决。
使用using namespace std;语句的同时要求标准库 的头文件都不得使用扩展名.h ,但用户自定义的头 文件可以带.h 。

//用using namespace std;打开标准库的标识符 #include <set> #include <iostream> void main() { using namespace std; //一劳永逸地打开 using std::set<int>::iterator; // 永久打开了iterator int a[100] = {10}; set<int> iSet(a,a+99); iterator it = iSet.find(25); cout<<" "<<*it<<endl; }
G():from namespace A
VC6.0的名空间不成熟
1. 在VC6.0中,名空间与友元冲突,编译器会报错。 只好舍弃其中的一个。 2. 名空间还会与模板冲突。
这只是VC不成熟的表现,到后来的VC7.0、8.0 就完全解决了。但这时你只能忍疼割爱,放 弃其中的一个。
名空间设计规范
首先,根据问题,分析分解产生“函数调用关 系图”。该图应标明三个层次的模块划分(程 序级、文件级、函数级)。注意要按调用关系 而非依赖关系划分。 按规则转换为“文件组模块”。 按模块从宏到微的次序,将个模块的输出归纳 于各头文件中,并以各名空间命名。 再以模块(最外层)为单位,归纳为上一级名空 间,产生更抽象的头文件。 最后分别实现这些资源。

若某程序的“函数调用关系图”如下:
文件1 模块1
f1 f2 h1 文件3 g2 g3 h2 h3 k2 k3 m4 m3 f3 k1 文件5 f4 main
模块2
g1
m1
文件2 文件4
n1 n2
文件6
k4 k5
模块3
转化为 “文件组模块”如下:
模块2 g1,g2,g3
h1
k1
文件1
f1
f2
f3 f1 f2 f3 f4 f4
模块3
m1
模块1
文件2
g1 g2 g3 g1,g2,g3
g1 g2 g3 g1,g2,g3
文件4
n1 n2
h2 n1 h3 n2
文件3
h1 h1 h1
模块2
// file1.h namespace f1 { void f1(); void f2(); void f3(); void f4(); } // file2.h namespace f2 { void g1(); void g2(); void g3(); }
C/C++的命名原则

C/C++/C#/Java等语言都遵循的命名原则:在同一 作用域内,不得命名相同名称的同种类标识符,否 则视为“名冲突”语法错误。 “命名冲突”:在不同文件模块中使用了相同的名 字来表示不同的事物,当这些模块一旦由头文件导 入凑到了一起,则会引起名称的混乱。 名空间如同磁盘的子目录,标识符如同各子目录下 的文件。名空间如同子目录一样可以嵌套。使用名 空间如同使用文件时要加路径,不过那是用于文件 的,名空间不能用,名空间有特定的使用方式。
欲引进多个名空间时,可在当前区域内使用如下语句: using namespace 空间名1; using namespace 空间名2; 当前区域是指using指令所在的位 臵,如函数内、文件内等等 此时在两个名空间有同名标识符时会产生二义性。区分 的方法同上。

主函数不可放入任何名空间中。

在新的C++标准程序库中,系统所用的标识符都声明 在命名空间std中,而未使用名空间的程序,都使用 带.h的头文件,则意味着其标识符都是全局的。
“命名空间“的诞生
在一大片土地上生活着一群人。开始人数不 是太多时尚无同名问题,可是后来,人越来越 多,同名的现象越来越突出。 于是,人们就把这大片的地域划分成较小的 块,每个块给予命名。由于块的分割,人名都 加上了前缀,同名的现象得到了控制。若还区 别不开,则进一步将块划小。 就这样,命名空间诞生了。
1规则的示例:
在名字空间之外使用时要时刻带空间名: namespace Parser { double prim( bool);
double term( bool);
} double Parser::prim( bool get) {} double Parser::term( bool get) {}

使用名空间的方法:
1. 将使用的标识符前加名空间名——凡用就加: NS:: File obj; NS:: Fun (); 这属于“单个一次性开放”,且每次使用都得加。 尽管繁琐,但小巧灵活。此法用于使用的名空间 标识符个数、次数较少时。 2. 用using声明,一劳永逸地指定,免去了每次必须指 定的繁琐。属于“单个一劳永逸开放”,: 例如,经过以下声明: using NS::File; 在当前作用域中就可以不再加标识地直接引用File。 此法用于使用的名空间标识符次数频繁时。
相关文档
最新文档