为什么要有namespace?
namespace是用来解决命名冲突(名字污染)的问题的。看看下面的代码:
#include <cstdlib>
int rand = 10;
int main()
{
return 0;
}
可以看到,这段代码什么都没干,就定义了一个全局变量rand。然而,全局也有一个库函数rand,就产生了命名冲突。
如果是C语言,为了解决这个问题,就不得不把变量名改了,比如改成rand1。
#include <stdlib.h>
int rand1 = 10;
int main()
{
return 0;
}
然而在C++中,只需要用命名空间隔离这个变量,让这个变量本地化,就可以解决命名冲突的问题。注意namespace的语法,rand属于namespace xbl这个命名空间域,而库函数rand属于全局域,虽然这两个标识符名字相同,但处于不同的域中,就不会冲突了。
#include <cstdlib>
namespace xbl
{
int rand = 10;
}
int main()
{
return 0;
}
namespace里可以定义那些标识符?
namespace里可以定义变量、函数、类型。比如:
namespace xbl
{
// 变量
int rand = 10;
// 函数
int add(int x, int y)
{
return x + y;
}
// 类型
struct list_node
{
int _value;
list_node* _prev;
list_node* _next;
};
}
注意到变量rand,函数add,类型list_node都在namespace xbl这个域的限定下,哪怕全局也有同样名字的标识符,也不会有命名冲突。
namespace如何使用?
方法一:使用作用域限定符::
,也就是两个冒号。以下代码分别访问了命名空间域namespace xbl里的变量rand、函数add、和类型list_node。
xbl::rand = 100;
int ret = xbl::add(3, 5);
xbl::list_node n;
方法二:使用using xxx::yyy;
展开命名空间中的某一个标识符,这样这个标识符就不受命名空间的限制了,相当于变成了全局的。
using xbl::add;
int main()
{
int ret = add(3, 5);
return 0;
}
方法三:使用using namespace xxx;
展开整个命名空间,此时命名空间里的所有标识符都变成全局的。以下代码展开了标准库的命名空间std,而cout和endl都属于namespace std,展开后可以直接使用。
#include <iostream>
using namespace std;
int main()
{
int a = 10;
cout << a << endl;
return 0;
}
namespace的细节问题
细节一:命名空间是可以嵌套的。
namespace xbl
{
int rand = 10;
int add(int x, int y)
{
return x + y;
}
struct list_node
{
int _value;
list_node* _prev;
list_node* _next;
};
namespace xbl1
{
int rand = 20;
}
}
这里namespace xbl里嵌套了namespace xbl1。访问时可以使用作用域限定符,xbl::rand
访问的就是10,xbl::xbl1::rand
访问的就是20。
细节二:指定访问全局的标识符rand,可以直接写::rand
。
细节三:同一个工程中可以有多个同名的命名空间,同名的命名空间会合并。如标准库的头文件中,一般都有namespace std,最终namespace std会合并。