关于namespace
由于大型程序常会使用多个独立开发的库,这些库又会定义大量全局的类、函数、模板等,不可避免的会发生某些名字相互冲突的情况,多个库将名字放置在全局命名中将导致命名空间污染。为防止名称冲突,可使用多个命名空间将全局的命名空间为不同的作用域。
一般而言,命名空间可由关键字namespace和名称组成,在单个文件内部使用也可单独由namespace关键字组成一个命名空间,称为未命名的命名空间,其中定义的变量拥有静态生命周期(在第一次使用前创建,直到程序结束才销毁)
namespace graph{
template<typename T>
class DenseGraph{
private:
T y;
public:
DenseGraph(T y):y(y){}
~DenseGraph(){}
};
// 命名空间可以嵌套
namespace edge{
...
}
// 命名空间可以内联
inline namespace vertix{
...
}
}
namespace{
template<typename T>
class DenseGraph{
private:
T y;
public:
DenseGraph(T y):y(y){}
~DenseGraph(){}
};
}
using声明、指示与作用域
using指示是以关键字using开头,后面是关键字namespace及其名字,using指示可以出现在全局作用域、局部作用域和命名空间作用域中,但不能出现在类的作用域中,using指示使得某个命名空间中所有的名字都可见。而using声明一次只引入命名空间的一个成员,且可出现在任何地方。
// using声明
std::vector<int> x(10);
std::cout << x << std::endl;
// using指示
namespace test{
int i=10, j=20;
}
int i = 100; //正确,不与test中i冲突
void fun(){
using namespace test; //引入命名空间test的名字
cout << test::i <<" "<< j <<endl; //使用test的变量
++i; //错误,不知道使用的哪个i
cout << ++::i <<endl; //全局i自加
cout << ++test::i <<endl; //test中的i自加
int j = 50; //正确,当前局部的变量
cout << ++j <<endl; //局部变量自加
}
运行得到结果如下:
10 20
101
11
51
注意1: 使用using指示一次性将某个命名空间的所有成员名字变得可见,如果通过using指示使用了多个库,则可能会出现命名空间污染
类、命名空间与作用域
对命名空间内部名字的查找由内向外依次查找每个外层作用域,外层作用域也可能是一个或多个嵌套命名空间,直到最外层的全局命名空间查找过程终止。
namespace A{
int i;
namespace B{
int i; //B中隐藏了A::i
int j;
int fun1(){
int j; //j是局部变量,隐藏了A::B::j
return i;
}
} //namespace B结束,B中定义的名字不再可见
int fun2{
return j; //错误,j没有定义
}
int j = i; //用A::i进行初始化
}
namespace A{
int i,k;
class test{
public:
test():i(0,j(0)){} //正确,初始化test::i和test::j
int fun1(){return k;} //返回A::k
int fun2(){return h;} //错误,未定义h
int fun3();
private:
int i,j;
};
int h = i;
}
int A::test::fun3(){return h;} //正确,返回A::h
当类声明一个友元时,该友元声明并没有使得友元本身可见,但一个另外的未声明的类或函数如果第一次出现在友元声明中,则认为它是最近的外层命名空间成员。
namespace A{
class test{
friend void fun();
friend void f(const test&);
};
}
int main(){
A::test obj;
f(obj); //正确,通过在A::test中的友元声明找到A::f
fun(); //错误,A::fun没有被声明
}
namespace与重载
//实参相关的重载
namespace A{
class test{}
void display(const test&){}
}
class test2:public A::test{}
int main(){
test2 t;
display(t);
return 0;
}
//using指示与重载
namespace A{
extern void print(int);
extern void print(double);
}
void print(const std::string &); //普通声明
using namespace A;
void fun(int val){
print("valuse: "); //全局print函数
print(val); //调用A::print(int)
}
//多个using指示的重载
namespace A{
int print(int);
}
namespace B{
double print(double);
}
using namespace A;
using namespace B;
long print(long);
int main(){
print(1); //调用A::print(int)
print(3.1415); //调用B::print(double)
return 0;
}
References:
- 《Primer c++》第五版