31、C++ Primer 4th 笔记,命名空间

时间:2022-10-11 00:41:47

1、命名空间能够划分全局命名空间。一个命名空间是一个作用域。

2、命名空间可以在全局作用域或其它作用域内部定义,但不能在函数或类内部定义。可以在命名空间中放入可以出现在全局作用域的任意声明。

3、命名空间作用域不能以分号结束。

4、命名空间是累积的。一个命名空间的分离部分可以分散在多个文件中。

示例

namespace namespace_name
{
}

    既可以定义新的命名空间,也可以添加到现存命名空间中。

5、命名空间定义可以不连续意味着,可以用分离的接口文件和实现文件构成命名空间。因此,可以用与管理自己的类和函数定义相同的方法来组织命名空间。

示例

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
}

也可以在命名空间定义的外部定义命名空间成员,用类似于在类外定义类成员的方法。

6、定义在全局作用域的名字(在任意类、函数或命名空间外部声明的名字)是定义在全局命名空间的。全局命名空间是隐式声明的,没有名字,通过::mem_name引用全局命名空间的成员。

7、未命名的命名空间的定义局部于特定文件,可以在给定文件中不连续,从不跨越多个文本文件。每个文件都有自己的未命名的命名空间。

未命名的命名空间中定义的名字可以在定义该命名空间的在的作用域中找到。

如果头文件定义了未命名的命名空间,那么,在每个包含该头文件的文件中,该命名空间中的名字将定义不同的局部实体。

因该避免文件静态而使用未命名的命名空间代替。

8、除了在函数或其他作用域内部,头文件不应该包含using批示或using声明。

9、命名空间别名:

一个命名空间可以有许多别名,所有别名以及原来的命名空间都可以互换使用。

示例

namespace primer = cplusplus_primer;

10using指示与using声明

示例

namespace namespace_myname
{
	int i;
}
using namespace namespace_myname; //using directive
using namespace_myname::i; //using declaration

using声明引起的二义性错误在声明点而不是使用点检测,因此更容易发现和修正。

11、实参相关的查找与类类型形参

示例

std::string s;
//ok: calls std::getline(std::istream&, const std::string&)
getline(std::cin, s);

接受类类型形参(或类类型指针及引用形参)的函数(包括重载操作符),以及与类本身定义在同一命名空间中的函数(包括重载操作符),在类类型对象(或类类型的引用及指针)作为实参的时候是可见的。

当编译器看到 getline 函数的使用getline(std::cin, s);的时候,它在当前作用域,包含调用的作用域以及定义 cin 的类型和string 类型的命名空间中查找匹配的函数。因此,它在命名空间 std 中查找并找到由 string 类型定义的 getline 函数。

12、有一个或多个类类型形参的函数的名字查找包括每个形参类型的命名空间。

13、重载与using directive,declaration

1)重载与using声明

示例

using NS::print(int); // error: cannot specify parameter list
using NS::print; // ok: using declarations specify names only

    如果命名空间内部的函数是重载的,那么该函数名字的using声明声明了所有具有该函数名字的函数。

2)重载与using指示

    如果命名空间函数与命名空间所在的作用域中声明的函数同名,就将命名空间成员加到重载集合中。

示例

namespace libs_R_us {
	extern void print(int);
	extern void print(double);
}
void print(const std::string &);
// using directive:
using namespace libs_R_us;
// using directive added names to the candidate set for calls to print:
// print(int) from libs_R_us
// print(double) from libs_R_us
// print(const std::string &) declared explicitly
void fooBar(int ival)
{
	print("Value: "); // calls global print(const string &)
	print(ival); // calls libs_R_us::print(int)
}

14、命名空间与模板

    模板的显式特化必须在定义通用模板的命名空间中声明,否则,该特化将与它所特化的模板不同名。

    有两种定义特化的方式:一种是重新打开命名空间并加入特化的定义(命名空间定义是不连续);或者,可以用与在命名空间定义外部定义命名空间成员相同的方式来定义特化:使用由命名空间名字限定的模板名定义特化。

    为了提供命名空间中所定义模板的自己的特化,必须保证在包含原始模板定义的命名空间中定义特化。