命名空间
- 1、作用:防止名字冲突。一个命名空间是一个作用域.
- 2、定义:
namespace cplusplus_primer { class Sales_item { /* ... */}; Sales_item operator+(const Sales_item&, const Sales_item&); class Query { public: Query(const std::string&); std::ostream &display(std::ostream&) const; // ... }; class Query_base { /* ... */}; } //这段代码定义了名为 cplusplus_primer 的命名空间,它有四个成员:两个类,一个重载的操作符,一个函数。
- 3、命名空间可以是不连续的:与其他作用域不同,命名空间可以在几个部分中定义。命名空间由它的分离定义部分的总和构成,命名空间是累积的。
- 4、接口和实现的分离
作用:保证函数和其他我们需要的名字只定义一次,但相同的声明可以在任何使用该实体的地方见到。
实现:定义类的命名空间成员,以及作为类接口的一部分的函数声明与对象声明,可以放在头文件中,使用命名空间成员的文件可以包含这些头文件。
命名空间成员的定义可以放在单独的源文件中。
- 5、全局命名空间:隐式声明的,存在于每个程序中。
全局变量是定义在全局命名空间里的。可以用作用域操作符引用全局命名空间的成员。因为全局命名空间是隐含的,它没有名字,所以记号::member_name //引用全局命名空间的成员
建议: 定义多个不相关类型的命名空间应该使用分离的文件,表示该命名空间定义的每个类型。 |
- 6、定义本书的命名空间
//使用将接口和实现分离的策略,可以将 cplusplus_primer 库定义在几个分离的文件中。本书第一部分建立的 Sales_item 的声明及其相关函数可以放在 Sales_item.h 中,第十五章的 Query 类的定义以及相关函数放在 Query.h 中,以此类推。对应的实现文件可以是 Sales_item.cc 和 Query.cc:: // ---- Sales_item.h ---- namespace cplusplus_primer { class Sales_item { /* ... */}; Sales_item operator+(const Sales_item&, const Sales_item&); // declarations for remaining functions in the Sales_item interface } // ---- Query.h ---- namespace cplusplus_primer { class Query { public: Query(const std::string&); std::ostream &display(std::ostream&) const; // ... }; class Query_base { /* ... */}; } // ---- Sales_item.cc ---- #include "Sales_item.h" namespace cplusplus_primer { // definitions for Sales_item members and overloaded operators } // ---- Query.cc ---- #include "Query.h" namespace cplusplus_primer { // definitions for Query members and related functions }
//使用我们的库的程序可以包含需要的头文件,那些头文件中的名字定义在命名空间 cplusplus_primer 内部: // ---- user.cc ---- // defines the cplusplus_primer::Sales_item class #include "Sales_item.h" int main() { // ... cplusplus_primer::Sales_item trans1, trans2; // ... return 0; }
- 7、定义命名空间成员
//在命名空间内部定义的函数可以使用同一命名空间中定义的名字的简写形式: namespace cplusplus_primer { // members defined inside the namespace may use unqualified names std::istream& operator>>(std::istream& in, Sales_item& s) { // ... } //也可以在命名空间定义的外部定义命名空间成员,用类似于在类外部定义类成员的方式:名字的命名空间声明必须在作用域中,并且定义必须指定该名字所属的命名空间: // namespace members defined outside the namespace must use qualified names cplusplus_primer::Sales_item cplusplus_primer::operator+(const Sales_item& lhs, const Sales_item& rhs) { Sales_item ret(lhs); // ... }
- 8、全局命名空间
全局变量是定义在全局命名空间里的,全局命名空间是隐式声明的,存在于每个程序中。
可以用作用域操作符引用全局命名空间的成员。因为全局命名空间是隐含的,它没有名字,所以记号
::member_name//引用全局命名空间的成员。
- 9、嵌套命名空间
作用:当库提供者需要防止库中每个部分的名字与库中其他部分的名字冲突的时候,嵌套命名空间是很有用的。
先看如下代码:
//命名空间 cplusplus_primer 现在包含两个嵌套命名空间:名为 QueryLib 的命名空间和名为 Bookstore 的命名空间。 namespace cplusplus_primer { // first nested namespace: // defines the Query portion of the library namespace QueryLib { class Query { /* ... */ }; Query operator&(const Query&, const Query&); // ... } // second nested namespace: // defines the Sales_item portion of the library namespace Bookstore { class Item_base { /* ... */ }; class Bulk_item : public Item_base { /* ... */ }; // ... } }
如果出现同名情况,cplusplus_primer中的名字将会被QueryLib、Bookstore中的名字屏蔽。嵌套命名空间内部定义的名字局部于该命名空间。
cplusplus_primer::QueryLib::Query//嵌套命名空间 QueryLib 中类Query的声明
- 10、未命名的命名空间:在定义时没有给定名字的命名空间。
注意:未命名的命名空间与其他命名空间不同,它可以在给定文件中不连续,但不能跨越文件,每个文件有自己的未命名的命名空间。
作用:用于声明局部于文件的实体。
特点:在未命名的命名空间中定义的变量在程序开始时创建,在程序结束之前一直存在。
未命名的命名空间中定义的名字可直接使用。
未命名的命名空间中定义的名字只在包含该命名空间的文件中可见。如果另一文件包含一个未命名的命名空间,两个命名空间不相关。两个命名空间可以定义相同的名 字,而这些定义将引用不同的实体。
注意:如果头文件定义了未命名的命名空间,那么,在每个包含该头文件的文件中,该命名空间中的名字将定义不同的局部实体。 |
//如果在文件的最外层作用域中定义未命名的命名空间,那么,未命名的空间中的名字必须与全局作用域中定义的名字不同: int i; // global declaration for i namespace { int i; } // error: ambiguous defined globally and in an unnested, unnamed namespace i = 10; //如果未命名的命名空间是嵌套的,其中的名字按常规方法使用外围命名空间名字访问: namespace local { namespace { int i; } } // ok: i defined in a nested unnamed namespace is distinct from global i local::i = 42;
未命名的命名空间取代文件中的静态声明:
在标准 C++ 中引入命名空间之前,程序必须将名字声明为static,使它们局部于一个文件。文件中静态声明的使用从 C 语言继承而来,在 C 语言中,声明为static 的局部实体在声明它的文件之外不可见。
C++ 不赞成文件静态声明。不造成的特征是在未来版本中可能不支持的特征。应该避免文件静态而使用未命名空间代替。
- 11、命名空间别名:将较短的同义词与命名空间名字相关联。
namespace cplusplus_primer { /* ... */ }; namespace primer = cplusplus_primer; //也可以引用嵌套的命名空间 cplusplus_primer::QueryLib::Query tq; namespace Qlib = cplusplus_primer::QueryLib; Qlib::Query tq;12、using
namespace blip { int bi = 16, bj = 15, bk = 23; // other declarations } int bj = 0; // ok: bj inside blip is hidden inside a namespace void manip() { // using directive - names in blip "added" to global scope using namespace blip; // clash between ::bj and blip::bj // detected only if bj is used ++bi; // sets blip::bi to 17 ++bj; // error: ambiguous // global bj or blip::bj? ++::bj; // ok: sets global bj to 1 ++blip::bj; // ok: sets blip::bj to 16 int bk = 97; // local bk hides blip::bk ++bk; // sets local bk to 98 }⑴如果在全局作用域中定义 blip,则 blip 的成员看来好像是声明在全局作用域的一样。
⑵