文章目录

  • 1.命名空间的定义
  • 2.使用命名空间的成员
  • 3.命名空间、类与作用域



命名空间的作用是为了解决命名冲突问题。

1.命名空间的定义

命名空间主要由namespace关键字定义,其定义方式为:

namespace cpp_primer{
	/*类、函数、变量、模板等*/
}//命名空间作用域后不需要加";"

每个命名空间都有一个作用域
命名空间作用域内的成员我们可以通过作用域符号进行访问。其访问方式为:空间名::成员名

std::cout;//使用便准命名空间std内的成员cout

命名空间可以是不连续的
命名空间不一定是连续的,一个命名空间可在不同的位置或者不同的文件中添加成员。如下:

namespace nsp{
	//相关声名
}

如果命名空间nsp为声名则声名新的命名空间,如果已经声名就象nsp中添加新的成员。命名空间的不连续性使得我们可以在同一个命名空间内实现接口的定义和实现分离。

//xxxx.h文件
#include<string>
namespace cpp_primer{
	//声名和定义
}


//xxxx.cpp文件
#include<xxxx.h>
namespace cpp_primer{
	//接口的实现
}


//接口的使用
#include<xxxx.h>
int main()
{
	using cpp_primer::XXXX;
	/*......*/
}

上述的头文件必须写在命名空间之前,否则将会把头文件所包含的内容全部写入命名空间中没这样将会导致错误。
命名空间的成员的实现可以在命名空间之外实现,其实现方式类似于类成员函数的类外实现。

内联命名空间
内联命名空间中的成员可以在外层的命名空间中直接使用,内联命名空间的定义方式是在namespace前面加上关键名字inline:

namespace test{
	inline namespace test_a{
		int a;
	}
	namespace test_b{
		int b;
	}
}

int main()
{
	cout<<test::a;//a是内联的,外层命名空间可以直接访问
	cout<<test::test_b::b;//b所在的命名空间不是内联的,因此需要加上命名空间名。
}

2.使用命名空间的成员

命名空间成员的是使用可以采用命名空间名加作用域加成员名来访问,但是这种访问方式有些繁杂,因此以下方法用于成员的访问更简单

命名空间别名
我们可以给命名空间一个更简单的别名,这样我们使用其成员函数将会更加的简单,启用别名的方法如下:

namespace pri=cpp_primer;

pri::xxxx;//等价于cpp_primer::xxxx

命名空间的别名和原来的完全名字等价。

using声名单个成员
使用using声名空间中的函数可以一次把一个成员引入到当前使用成员的作用域中,该成员的有效范围为从using声名开始到该声名结束。

namespace test{
	int i;
	int j;
}

int main()
{
	using test::i;//在这条语句之后i都是可以使用的,相当于把test中的i引入到命名空间中了。
	i=1024;
	cout<<i;
}

using指示整个命名空间
我们还可以一次性的将整个命名空间的内容引入到某个作用域中。如下:

namespace test{
	int i;
	int j;
}

int main()
{
	using namespace test;//命名空间中的所有内容均在作用域内可用
	i=1024;
	cout<<i;
	j=2048;
	cout<<j;
}

但是将整个命名空间都引入到作用域中会导致命名空间污染,或者命名的冲突,也将导致程序书写复杂。

namespace test{
	int i;
	int j;
}
int i=0;//正确,这是命名空间中的i将被隐藏
int main()
{
	using namespace test;//命名空间中的所有内容均在作用域内可用
	i=1024;//错误,导致命名冲突,
	::i=1024;//正确,使用全局的i
	test::i=1024;//正确,使用test中的i
	j=2048;//不会产生冲突,使用test中的i;
	cout<<j;
}

3.命名空间、类与作用域

命名空间中的成员的查找类似于异常捕捉,由内层向外层逐渐的展开。
函数实参为类的类型
当一个函数的实参为类的类型时,函数执行的时候会在实参类以及他的基类所在的命名空间中去查找函数,找到函数即可进行调用。

namespace A{
	class C{
		/*......*/
	}
void fun(const C&);
}

int main()
{
	C c;
	fun(c);//能正确调用;
}

fun©函数能够被正确的调用因为参数为类的类型,则将会在C类和C的基类所在的命名空间中查找是否存在函数fun;

using和重载
当我们用using引入单个命名空间的成员时,我们引入的是该成员的名字,也就是说我们会将该命名空间中的所有同名的函数都引入到这个作用域中。

using NS::print(int);//错误,不能带参数
using NS::print;//正确,引入所有的同名函数。

当我们的作用域中存在函数名和参数都和命名空间中的一样时,程序将会出错。
但是如果我们用using namespace std这种方式引入整个命名空间,则当出现相同的函数名和参数时,并不会报错,调用时加上作用域限定即可。