当前位置:
文档之家› 7第七讲——名空间和RTTI
7第七讲——名空间和RTTI
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
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; }
使用名空间的方法:
1. 将使用的标识符前加名空间名——凡用就加: NS:: File obj; NS:: Fun (); 这属于“单个一次性开放”,且每次使用都得加。 尽管繁琐,但小巧灵活。此法用于使用的名空间 标识符个数、次数较少时。 2. 用using声明,一劳永逸地指定,免去了每次必须指 定的繁琐。属于“单个一劳永逸开放”,: 例如,经过以下声明: using NS::File; 在当前作用域中就可以不再加标识地直接引用File。 此法用于使用的名空间标识符次数频繁时。
G():from namespace A
VC6.0的名空间不成熟
1. 在VC6.0中,名空间与友元冲突,编译器会报错。 只好舍弃其中的一个。 2. 名空间还会与模板冲突。
这只是VC不成熟的表现,到后来的VC7.0、8.0 就完全解决了。但这时你只能忍疼割爱,放 弃其中的一个。
名空间设计规范
首先,根据问题,分析分解产生“函数调用关 系图”。该图应标明三个层次的模块划分(程 序级、文件级、函数级)。注意要按调用关系 而非依赖关系划分。 按规则转换为“文件组模块”。 按模块从宏到微的次序,将个模块的输出归纳 于各头文件中,并以各名空间命名。 再以模块(最外层)为单位,归纳为上一级名空 间,产生更抽象的头文件。 最后分别实现这些资源。
// 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;
namspace B { class File; void Fun (); namspace C //名空间可以嵌套。 { class File; void Fun (); } }
匿名空间
“匿名空间”:设定一个无名的命名空间,将标识符 集合其内,由于无名,本文件的域外可以无限制地 使用该空间的标识符,省却了定义时的static,使用 时也节省了空间名前缀。但别的文件不可使用。因 此匿名空间的作用相当于C时代的静态全局变量 。 如: namspace { class File; void Fun (); } 匿名空间也可以跨文件追加。 一个编译单元只可有一个匿名空间。
然后,在源程序开发时,就可以将这三个模块 文件作为资源使用。当然,要对各头文件中所 涉及的函数予以实现。
名空间尽管发源于模块的划分和隔离,服务于 模块设计的开发模式,但从中受益的不仅是模 块,还有数据的使用。当然数据要求更细致的 服务,名空间就显粗糙了些,更精细的是类。
四个强制转换运算符 RTTI的概念 RTTI的两种使用方法 合理使用RTTI
新增的四个强制类型转换符
“强制”的含义: 在告诉编译器: “我知道你不愿意这样做,可是你必须做。尽管 执行吧,后果由我负责!”
const_cast
对象自身.
static_cast
除去对象的常属性。转换的是表达式而非 形式:const_cast < type > ( object )
欲引进多个名空间时,可在当前区域内使用如下语句: 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) {}
3. “全面开放,一劳永逸”
用指示符using:
using namespace std;语句后,名空间std中的所有 标识符都在本作用域中开放,可直接使用。此法将引 起标识符的“全面冲突”。 此法用于使用的名空间标识符个数、次数都很多时。 此法将因别的名空间的引进而产生“名冲突”。编 译器的仲裁准则是“外来服从本层”。它的在外层, 你的在内层,内层屏蔽外层。被屏蔽的同名者可用空 间名::标识符 来区分。 用2方法打开时可能发生的“个别冲突”,也用此 法解决。
C/C++的命名原则
C/C++/C#/Java等语言都遵循的命名原则:在同一 作用域内,不得命名相同名称的同种类标识符,否 则视为“名冲突”语法错误。 “命名冲突”:在不同文件模块中使用了相同的名 字来表示不同的事物,当这些模块一旦由头文件导 入凑到了一起,则会引起名称的混乱。 名空间如同磁盘的子目录,标识符如同各子目录下 的文件。名空间如同子目录一样可以嵌套。使用名 空间如同使用文件时要加路径,不过那是用于文件 的,名空间不能用,名空间有特定的使用方式。
C++语言程序设计
命名空间和RTTI
本章主要内容
命名空间 RTTI的概念 RTTI的两种使用方法 合理使用RTTI
在无“命名空间“的年代
记得在五六十年代,火车站的候车室(还有 候船厅)里都有块“旅客留言板”。人们在上 面留下自己的纸条。“小李,我已乘xx次列车 走了。”、“老王,我已抵连,现住在xx旅 馆。” ... 开始,旅客较少时很方便。但随着 旅客的增多,由于简称、同名等造成的误解, 带来的不是方便,而是混乱。 可见公共资源的是不可滥用的,必须加以限 制。
使用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; }
命名空间(namespace)
“命名空间”:为语言再设定一个命名的作用域 (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() }
名空间的性质
“名空间”是跨越文件的。它不是简单的包含了文件, 而是更灵活的超越了文件。是个逻辑概念,就如同活动 在校内外的学生依然从属于某系某班级一样。