命名空间
在 C++ 中,名称( name )可以是符号常量、变量、宏、函数、结构、枚举、类和对象等等。为了避免,在大规模程序的设计中,以及在程序员使用各种各样的 C++ 库时,这些标识符的命名发生冲突,标准 C++ 引入了关键字 namespace (命名空间 / 名字空间 / 名称空间 / 名域),可以更好地控制标识符的作用域。
MFC 中并没有使用命名空间,但是在 .NET 框架、 MC++ 和 C++/CLI 中,都大量使用了命名空间。
1 )命名空间引入
命名空间( namespace )是一种描述逻辑分组的机制,可以将按某些标准在逻辑上属于同一个类的声明放在同一个命名空间中。
原来 C++ 标识符的作用域分成三级别:代码块( { …… } ,如复合语句和函数体)、类和全局。现在,在其中的类和全局之间,标准 C++ 又添加了命名空间这一个作用域级别。(上一篇文章“C++标示符的作用域 ”)
标准 C++ 库(不包括标准 C 库)中所包含的所有内容(包括常量、变量、结构、类和函数等)都被定义在命名空间 std ( standard 标准)中。2 )定义命名空间 有两种形式的命名空间——有名的和无名的。
有名的命名空间:
namespace 命名空间名 {
...
成员
}
无名的命名空间 :
namespace {...
成员
}
命名空间名 :: 成员名
例如:
// out.h
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() 的声明
}
void f(); // 命名空间 Outer 的成员 f() 的声明
// namespace Inner2; // 错误 ,不能声明子命名空间
}
void Outer::f() {i--;} // 命名空间 Outer 的成员 f() 的外部定义
void Outer::Inner::h() {i--;} // 命名空间 Inner 的成员 h() 的外部定义
// namespace Outer::Inner2 {/* …… */} // 错误 ,不能在外部定义子命名空间
注意:
不能在命名空间的定义中声明( 另一个嵌套的)子命名空间,只能在命名空间的定义中定义 子命名空间。
也不能直接使用“命名空间名 :: 成员名 ……”定义方式,为命名空间添加新成员,而必须先在命名空间的定义中添加新成员的声明。
另外,命名空间是开放的,即可以随时把新的成员名称加入到已有的命名空间之中去。方法是,多次声明和定义同一命名空间,每次添加自己的新成员和名称。例如:
//a.cpp
namespace Android {
int a;
void f();
} // 现在 A 有成员 i 和 f()
//b.cpp
namespace Android {
int b;
void g();
}
// 现在 Android 有成员 a 、 f() 、 b 和 g()
还可以用多种方法,来组合现有的命名空间,让它们为我所用。例如:
namespace My_space {
using namespace His_string; //指定整个空间
using namespace Her_vector;
using Your_list::List; //指定该空间某个成员
void my_f(String &, List &);
}
……
using namespace My_lib;
……
Vector<String> vs[5];
List<int> li[10];
my_f(vs[2], li[5]);
3 )使用命名空间
a) 作用域解析运算符( :: )
对命名空间中成员的引用,需要使用命名空间的作用域解析运算符 :: 。例如:
// out1.cpp
#include "out.h"
#include <iostream>
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;
}
b) using 指令 ( using namespace )
为了省去每次调用 Inner 成员和标准库的函数和对象时,都要添加 Outer::Inner:: 和 sta:: 的麻烦,可以使用标准 C++ 的 using 编译指令来简化对命名空间中的名称的使用。格式为:
using namespace 命名空间名 [:: 命名空间名…… ];
在这条语句之后,就可以直接使用该命名空间中的标识符,而不必写前面的命名空间定位部分。因为 using 指令,使所指定的整个命名空间中的所有成员都直接可用。例如:
// out2.cpp
#include "out.h"
#include <iostream>
// using namespace Outer; // 编译错误,因为变量 i 和函数 f() 有名称冲突
using namespace Outer::Inner;
using namespace std;
int main ( ) {
Outer::i = 0;
Outer::f(); // Outer::i = -1;
f(); // Inner::f() , Outer::i = 0;
i = 0; // Inner::i
g(); // Inner::g() , Inner::i = 1;
h(); // Inner::h() , Inner::i = 0;
cout << "Hello, World!" << endl;
cout << "Outer::i = " << Outer::i << ", Inner::i = " << i << endl;
}
c) using 声明 ( using )
使用 using 声明来简化对命 空间中的名称的使用
格式为:using 命名空间名 :: [内部 命名空间名 :: …… ] 成员名 ;
注意,关键字 using 后面并没有跟关键字 namespace ,而且最后必须为命名空间的成员名(而在 using 编译指令的最后,必须为命名空间名)。
与 using 指令不同的是, using 声明只是把命名空间的特定成员的名称,添加该声明所在的区域中,使得该成员可以不需要采用,(多级)命名空间的作用域解析运算符来定位,而直接被使用。但是该命名空间的其他成员,仍然需要作用域解析运算符来定位。例如:
// out3.cpp
#include "out.h"
#include <iostream>
using namespace Outer ; // 注意,此处无 ::Inner
using namespace std;
// using Inner::f; // 编译错误,因为函数 f() 有名称冲突
using Inner::g; // 此处省去 Outer:: ,是因为 Outer 已经被前面的 using 指令作用过了
using Inner::h;
int main ( ) {
i = 0; // Outer::i
f(); // Outer::f() , Outer::i = -1;
Inner:: f(); // Outer::i = 0;
Inner:: i = 0;
g(); // Inner::g() , Inner::i = 1;
h(); // Inner::h() , Inner::i = 0;
cout << "Hello, World!" << endl;
cout << "Outer::i = " << i << ", Inner::i = " << Inner::i << endl;
}