一个命名空间包含两部分:首先是关键字namespace,随后是命名空间的名字。在命名空间名字后面是一系列由花括号括起来的声明和定义。只要能出现在全局作用域中的声明就能置于命名空间内,主要包括:类、变量(及其初始化操作)、函数(及其定义)、模板及其它命名空间:
namespace cplusplus_primer { class Sales_data {/* ... */}; Sales_data operator+(const Sales_data&, const Sales_data &); class Query {/* ... */}; class Query_base {/* ... */}; } //命名空间结束后无须分号,这一点跟快类似
上面的代码定义了一个名为cplusplus_primer的命名空间,该命名空间包含四个成员:三个类和一个重载+运算符。
和其它名字一样,命名空间的名字也必须在定义它的作用域内保持唯一。命名空间既可以定义在全局作用域内,也可以定义在其它命名空间中,但是不能定义在函数或类的内部。
每个命名空间都是一个作用域
和其它作用域类似,命名空间中的每个名字都必须表示该空间的唯一实体。因为不同的命名空间的作用域不同,所以在不同的命名空间内可以有相同的名字。
定义在某个命名空间中的名字可以被该命名空间内的其它成员直接访问,也可以被这些成员内嵌作用域的任何单位访问。位于该命名空间之外的代码则必须明确指出所用的名字属于哪个命名空间:
cplusplus_primer::Query q = cplusplus_primer::Query("hello");
如果其它命名空间(比如说AddisonWesley)也提供了一个名为Query的类,并且希望我们使用这个类代替cplusplus_primer中定义的同名类,则可以按照如下方式修改代码:
AddisonWesley::Query q = AddisonWesley::Query("hello");
命名空间不是连续的
命名空间可以定义在几个不同的部分,这一点与其它作用域不太一样。编写如下命名空间的定义:
namespace nsp { //相关声明 }
可能是定义了一个名为nsp的命名空间,也可能是为已经存在的命名空间添加一些新成员。如果之前没有nsp的命名空间定义,则上述代码创建一个新的命名空间;否则上述代码打开已经存在的命名空间定义并为其添加一些新成员的声明。
命名空间可以是不连续的特性使得我们可以将几个独立的接口和实现文件组成一个命名空间。此时,命名空间的组织方式类似于我们管理自定义类及函数的方式:
- 命名空间的一部分成员的作用是定义类,以及声明作为接口的函数及对象,则这些成员应该置于头文件中,这些头文件将被包含在使用了这些成员的文件中。
- 命名空间成员的定义部分则置于另外的源文件中。
在程序中某些实体只能定义一次:如非内联函数、静态数据成员、变量等,命名空间中定义的名字也需要满足这一要求,我们可以通过上面的方式组织命名空间并达到目的。这种接口和实现分离的机制确保我们所需的函数和其它名字只定义一次,而只要是用到这些实体的地方都能看到对于实体名字的声明。
定义本书的命名空间
通过使用上述接口与实现分离的机制,我们可以将cplusplus_primer库定义在几个不同的文件中。Sales_data类的声明及其函数将置于Sales_data.h头文件中,Query将置于Query.h头文件中,以此类推。对应的实现文件将分别是Sales_data.cc和Query.cc:
// --- Sales_data.h --- // #include应该出现在打开命名空间的操作之前 #include <string> namespace cplusplus_primer { class Sales_data { /* ... */ }; Sales_data operator+(const Sales_data&, const Sales_data&); //Sales_data其它接口函数的声明 } // ---Sales_data.cc --- // 确保#include出现在打开命名空间的操作之前 #include "Sales_data.h" namespace cplusplus_primer { //Sales_data成员及重载运算符的定义 }
程序如果使用我们定义的库,必须包含必要的头文件,这些头文件中的名字定义在命名空间cplusplus_primer内:
// --- user.cc --- // Sales_data.h头文件的名字位于命名空间cplusplus_primer中 #include "Sales_data.h" int main() { using cplusplus_primer::Sales_data; Sales_data trans1, trans2; // ... //return 0; }
这种程序的组织方式提供了开发者和库用户所需的模块性。每个类仍组织在自己的接口和实现文件中,一个类的用户不必编译与其它类相关的名字。我们对用户隐藏了实现细节,同时允许文件Sales_data.cc和user.cc被编译并链接成一个程序而不会产生任何编译时错误或链接时错误。库的开发者可以分别实现每个类,相互之间没有干扰。
有一点需要注意,在通常情况下,我们不把#include放在命名空间内部。如果我们这么做了,隐含的意思是把头文件中所有的名字定义成该命名空间的成员。例如,如果Sales_data.h在包含string头文件之前就已经打开了命名空间cplusplus_primer,则程序将出错,i那位这么做意味着我们试图将命名空间std嵌套在cplusplus_primer中。
原文地址:https://www.cnblogs.com/bootblack/p/11429842.html