一、C++命名空间定义
一个中大型软件往往由多名程序员共同开发,会使用大量的变量和函数,不可避免地会出现变量或函数的命名冲突。当所有人的代码都测试通过,没有问题时,将它们结合到一起就有可能会出现命名冲突。
例如小李和小韩都参与了一个文件管理系统的开发,它们都定义了一个全局变量 fp,用来指明当前打开的文件,将他们的代码整合在一起编译时,很明显编译器会提示 fp 重复定义(Redefinition)错误。
为了解决合作开发时的命名冲突问题,C++ 引入了命名空间(Namespace)的概念。
二、命名空间的使用
(1)最简单的办法,在变量和函数前面加上命名空间的完整前缀:
#include <iostream>
using namespace std;
namespace nameA{
namespace nameB{
class NT{
public:
NT()
{
cout<<"this is my NT"<<endl;
}
};
}
}
int main(){
nameA::nameB::NT nt;
}
运行结果:
this is my NT
(2)也可以使用using namespace ×××
#include <iostream>
using namespace std;
namespace nameA{
namespace nameB{
class NT{
public:
NT()
{
cout<<"this is my NT"<<endl;
}
};
}
}
int main(){
using namespace nameA::nameB;
NT nt;
}
(3)你甚至可以使用using namespace+前缀组合的方式,处理嵌套的命名空间。
#include <iostream>
using namespace std;
namespace nameA{
namespace nameB{
class NT{
public:
NT()
{
cout<<"this is my NT"<<endl;
}
};
}
}
int main(){
using namespace nameA;
nameB::NT nt;
}
三、using namespace+前缀组合规则
一句话,前缀是编译器必须的考虑的,using namespace是编译器选择参考的。
加上using namespace后,编译器会尝试给前缀前面加上相应的修饰,但是也会到不加修饰的空间里面寻找,能且只能找到一个!
#include <iostream>
using namespace std;
namespace nameA{
namespace nameB{
class NT {
public:
NT()
{
cout<<"this is my NT"<<endl;
}
};
}
}
int i=0;
int main(){
using namespace nameA;
nameA::nameB::NT nt1;
nameB::NT nt2;
i++;
}
行为如下:
(1)尝试在nameA::nameA::nameB中找到NT类,找不到这个命名空间,终止。
(2)尝试在nameA::nameB中找到NT类,找到了,结束。
(3)尝试在nameA::nameB中找到NT类,定义nt2,找到了,结束。
(4)尝试在nameB命名空间中寻找,没有这个命名空间,结束。
(5)在nameA中找变量i,找不到,结束。
(6)在全局命名空间中找i,找到了。
有一个隐含过程,因为在最开始using namespace std,所以会在std空间里面找东西。
四、using namespace 的优先级。
using namespace可以声明在很多地方,可以在函数中,也可以在函数外,但是只要代码处于using namespace的作用域中,**各个using namespace就没有优先级!!!**所以要避免二义性报错。
(1)命名空间二义性
让编译器知道使用哪一个命名空间。
#include <iostream>
using namespace std;
namespace nameA{
namespace nameB{
class NT {
public:
NT()
{
cout<<"this is my NT"<<endl;
}
};
}
}
namespace nameB{
int i;
}
int main(){
using namespace nameA;
nameA::nameB::NT nt1;
nameB::NT; //报错,编译器不知道是哪一个命名空间。
}
编译器既可以使用命名空间nameB,又可以使用命名空间nameA::nameB,二者没有优先级,报错。
(2)命名空间中的成员歧义:
#include <iostream>
using namespace std;
namespace nameA{
namespace nameB{
class string {
public:
string()
{
cout<<"this is my string"<<endl;
}
};
}
}
int main(){
using namespace nameA::nameB;
string str; //报错,编译器不知道是标准库string还是自定义string
}
由于最开始using namespace std,编译器也会尝试在std中寻找string,也会在nameA::nameB中寻找string,二者没有优先级,歧义报错。