►大型应用程序经常使用来自不同厂商的开发库,几乎不可避免会使用相同的名字,也就是说一个库中定义的名字可能与其他库中的名字相同而产生冲突,使得程序员不能组合各自独立的开发库到一个程序中。
►命名空间是用来限定名字的解析和使用范围的,它是C++开发大型程序的工具之一。
►命名空间的原理是将全局作用域划分为一个一个的命名空间,每个命名空间是一个独立的作用域,在不同命名空间内部定义的名字彼此之间互不影响,从而有效的避免了命名空间污染。
命名空间的定义形式为:
►命名空间可以在全局作用域或其他命名空间内部定义,但不能在函数、结构体或类内部定义,且要保证命名空间之间不会出现名字冲突。
►在命名空间作用域内,可以包含以下内容:
① 变量、对象以及它们的初始化。
② 枚举常量。
③ 函数声明以及函数定义。
④ 类、结构体声明与实现。
⑤ 模板。
⑥ 其他命名
(1)每个命名空间是一个作用域
►定义在命名空间中的实体称为命名空间成员。命名空间中的每个名字必须是该命名空间中的唯一实体,不同命名空间可以具有同名成员。
在命名空间中定义的名字可以被命名空间中的其他成员直接访问,命名空间外部的代码必须指出名字定义在哪个命名空间中,即作用域运算符限定命名空间,形式为:
(2)命名空间可以是不连续的
►命名空间可以在几个部分中分开定义,即命名空间是累积的。一个命名空间可以分散在多个文件中。
(3)接口和实现分离
►命名空间可以不连续意味着可以做以下事情:
►命名空间成员如果是类,可以将作为类接口的函数声明和对象 声明放在头文件中,使用这些命名空间成员的文件可以包含这 些头文件。
►命名空间类成员的定义可以放在单独的源文件中。
(4)定义命名空间成员
►在命名空间内部定义的函数可以使用同一命名空间中定义的名字。
►也可以在命名空间外部定义命名空间成员:
►定义在全局作用域的名字(任何类、函数或命名空间外部声明的名字)是定义在全局命名空间中的。全局命名空间存在于每个程序中,是隐式的。
►可以用作用域运算符引用全局命名空间的成员:
(6)嵌套命名空间
►嵌套命名空间中的名字遵循名字规则:外围命名空间中声明的名字 被嵌套命名空间中同一名字的声明所屏蔽。
定义命名空间时如果没有给出命名空间名字,称为未命名的命名空间,定义形式为:
(1)未命名的命名空间中定义的名字可以直接使用,没有命名空间名字来限定它们。
(2)未命名的命名空间可以在给定文件中不连续,但不能跨越文件,每个文件有自己的未命名的命名空间。本质上在一个文件中所 有未命名的命名空间会被系统用同一个标识符代替,且区别于其他文件的标识符。
(3)未命名的命名空间专门用于声明局部于文件的实体。
(4)未命名的命名空间中定义的名字只在包含该命名空间的文件 中可见。如果另一文件包含一个未命名的命名空间,两个命名空间不相关,可以定义相同名字的实体。
1. 命名空间成员的使用
►引用命名空间成员的形式为:
(1)命名空间的别名
►可以为命名空间起一个别名来代替较长的命名空间名,形式为:
(2)using声明
可以使用using声明引入命名空间成员,形式为:
一个using声明一次只引入一个命名空间成员,它是的无论程序中使用那些名字,都非常明确。例如:
(3)using指示
using指示的形式为:
using指示使得特定命名空间的所有名字可见,没有限制。
2. 类和命名空间
►对命名空间内部使用的名字的查找遵循常规的C++名字查找规则:
在类作用域查找名字的时候,首先在成员本身中查找,然后在类中查找,然后检查外围作用域。当类包含在命名空间中的时候,发生 相同的查找:首先在成员中找,然后在类中找,再在外围命名空间中找。
(1)实参相关的查找与类类型形参
►有简单程序:
►接收类类型形参的函数,以及与类本身定义在同一命名空间的函数, 在用类类型对象作为实参的时候是可见的。
►当编译器在编译getline(std::cin,s); 的时候,它在当前的作用域以及 定义cin和string类型的命名空间中查找匹配的函数,进而在std命名 空间找到有string类型定义的getline函数,所以调用getline函数不 用std::限定。
(2)标准命名空间的使用
►标准库的所有名字都是在一个名为std的标准命名空间中定义的, 当程序中用到标准库时,需要使用std作用域限定。
►我们之前几乎所有的示例代码使用的都是std的using指示:
这样做程序可以不必对每个std成员(如cin、cout、endl)一一处 理。但是也导致程序和其他库出现冲突的机会多了起来。
使用std限定的一个好处就是对每个std成员做限定,例如:
►这样做虽然不方便,但是最大程度的避免了与标准命名空间的名字 冲突。
►也可以用如下方法: