命名空间(namespace)为防止名字冲突提供可控机制。一个命名空间是一个作用域,可以在命名空间内部定义自己的模板名、类型名、函数名,而不会与其它命名空间中的相同名字造成冲突。
namespace cplusplus_primer { class SalesItem { /* … */ }; SalesItem operator+(const SalesItem &, const SalesItem&); class Query { public: Query(const std::string&); std::ostream & display(std::ostream&) const; // … }; class QueryBase { /* … */ }; }
命名空间中的名字在该命名空间的作用域中必须是唯一的。命名空间可以在全局作用域或其他作用域内部定义,但不能在函数或类内部定义。命名空间作用域不以分号结束。
1. 每个命名空间是一个作用域
在命名空间中定义的名字可以被命名空间中的其他成员直接访问。命名空间外的代码必须指出名字定义在哪个命名空间中:
cplusplus_primer::Query q = cplusplus_primer::Query(“hello”); q.display(cout); // …
2. using声明
可以编写using声明来获得对经常使用的名字的直接访问:
using cplusplus_primer::Query;
在这个using声明之后,程序可以直接使用名字Query。
3. 命名空间可以是不连续的
一个命名空间可以分散定义在多个文件中。不过,如果命名空间的一个部分需要使用一个定义在另一文件中的名字,必须声明该名字。
namespace namespace_name { // declarations }
如果namespace_name不是引用前面定义的命名空间,则用该名字创建新的命名空间,否则,这个定义打开一个已存在的命名空间,并将新声明加到那个命名空间。
4. 接口和实现的分离
可以用分离的接口文件和实现文件构成命名空间。可以用与管理类和函数定义相同的方法来组织命名空间。定义多个不相关类型的命名空间应该使用分离的文件分别定义每个类型。
// sales_item.h namespace cplusplus_primer { class SalesItem { /* … */ }; SalesItem operator+(const SalesItem&, const SalesItem&); } // query.h namespace cplusplus_primer { class Query { public: Query(const std::string&); std::ostream & display(std::ostream&) const; }; } // sales_item.cpp #include “sales_item.h” namespace cplusplus_primer { // definitions for SalesItem members and overloaded operators } // query.cpp #include “query.h” namespace cplusplus_primer { // definitions for Query members and related functions }
5. 定义命名空间成员
可以在命名空间定义的外部定义命名空间成员,类似于在类外部定义类成员的方式。
// namespace members defined outside the namespace must use qualified names cplusplus_primer::operator+(const SalesItem&, const SalesItem&) { SalesItem ret(lhs); // … }
一旦看到完全限定的函数名,此函数就处于命名空间的作用域中。所以形参表和函数体中的命名空间成员引用可以使用非限定名。
6. 全局命名空间
定义在全局作用域的名字(在任意类、函数、命名空间外部声明的名字)是定义在全局命名空间(global namespace)中的。全局命名空间是隐式声明的,存在于每个程序中。在全局作用域定义实体的每个文件将那些名字加到全局命名空间。
全局命名空间是隐含的,没有名字,可以通过::member_name引用全局命名空间的成员。