命名空间
c++中,我们常常对不同的变量,函数,结构体,类和对象等进行命名,如果对于一个比较大的工程,频繁的命名不可避免的会发生命名冲突,为此,c++引入关键字namespace(命名空间),可以很好地控制标识符的作用域。
举个例子,如下面c++入门程序“helloworld”:
#include<iostream>
using namespace std;
int main()
{
cout << "hello world" << endl;
return 0;
}
那么这里的第二行代码 using namespace std; 有什么作用呢?
再比如下面这个程序:
#include<stdio.h>
#include<stdlib.h>
int rand = 0;
int main()
{
printf("%d", rand);
return 0;
}
在vs中会提示报错:“rand”: 重定义。那么这又是什么原因呢?
原来,这里发生了命名冲突,在库中已经有以rand为名的函数,如果我们这时候在全局域再定义一个变量rand,就会发生命名冲突。所以,我们使用关键字namespace修改如下:
namespace aaa
{
int rand = 0;
}
//同一个域里面不能定义同一个变量,而这里namespace bit又是一个命名空间域
int main()
{
//printf("%p", rand);//(默认去全局域找,函数名是函数的地址)就不会报错了,打印的是rand函数的地址
printf("%d", aaa::rand);//如果要打印这个值的话
return 0;
}
这样,编译器就不会报错了。所以命名空间在这里起的作用就是做名字隔离,防止命名冲突。除此之外,命名空间还可以定义函数、类型,如下列代码:
namespace aaa
{
int rand = 0;
void func()
{
printf("func()\n");
}
struct TreeNode
{
struct TreeNode* left;
struct TreeNode* right;
int val;
};
}
int main()
{
//printf("%d\n", aaa::rand);
//func();//直接这样写这个函数时调不到的
aaa::func();//去命名空间里面找
return 0;
}
命名空间还可以嵌套:
namespace sql
{
int a = 0;
namespace aaa
{
int rand = 0;
void func()
{
printf("func()\n");
}
struct TreeNode
{
struct TreeNode* left;
struct TreeNode* right;
int val;
};
}
}
int main()
{
printf("%d\n", sql::aaa::rand);
//func();//直接这样写这个函数时调不到的
sql::aaa::func();//去命名空间里面找
return 0;
}
注意:同一个工程中允许存在多个相同名称的命名空间,编译器最后会合成同一个命名空间中。
命名空间的展开
如对上面的程序,有时候需要频繁的使用命名空间中的变量或函数,每次都写诸如 aaa::rand;aaa::func 会觉得有些麻烦,那如果不想每次都写域名aaa,就用using namespace aaa;将aaa域展开,即让编译器先在全局域去找,如果没有还会到展开的aaa域中去找。如上面的“helloworld”程序,std是c++标准库的命名空间域,开头 using namespace std 的作用就是将标准库里面的内容都放到命名空间里面去。所以程序中涉及到std命名域中的对象就可以直接用。
但如果我们都用直接展开,把命名空间全部暴露出来,又涉及到设计隐私的问题。所以,我们通常会只把常用的展开,不常用的还是像上面一样,一个一个指定即可。