C++ using namespace
参考:http://en.cppreference.com/w/cpp/language/namespace#Using-directives
1 #include <stdio.h> 2 3 namespace A{ 4 struct S{ 5 S(){ 6 printf("A::S(int) called \n"); 7 } 8 }; 9 } 10 11 namespace B{ 12 struct S{ 13 S(){ 14 printf("B::S(int) called \n"); 15 } 16 }; 17 using namespace A; 18 S s; 19 } 20 21 int main() 22 { 23 using namespace B; 24 S s; 25 }
第23行讲述了using-directive(以下简称U.D.)的第一个效应:把B名字空间虚拟的引入22行和25行包裹的块(block)。当第24行,遇到S这个符号时,B::S也是候选者,所以,程序员节省了几个打字(B::S).
但是编译失败,因为17行,在B块中,引入了A名字空间。因此,第24行名字解析时,会遇到两个候选者:A::S 和 B::S。
第18行讲述了U.D.的第二个效应,当本块的名字和其它名字冲突时,编译器不报错,会选择本块的名字(就是第12行定义的S)。按此思路,可以修改上述编译失败的代码为:
#include <stdio.h> namespace A{ struct S{ S(){ printf("A::S(int) called \n"); } }; } namespace B{ struct S{ S(){ printf("B::S(int) called \n"); } }; using namespace A; S s; } int main() { struct S{ S(){ printf("main::S(int) called \n"); } }; using namespace B; S s; }
这意味着什么?一个unqualified name(例如:S s; 而不是A::S s;)会随着工程的庞大,有时会编译失败,有时会改变含义。难以管理,这是很多编程规范中,不建议using namespace std;放到头文件的原因。
局部使用只影响局部,所以不能一概否定U.D. 例如:
1 #include <stdio.h> 2 3 namespace A{ 4 struct S{ 5 S(){ 6 printf("A::S(int) called \n"); 7 } 8 }; 9 } 10 11 namespace B{ 12 struct S{ 13 S(){ 14 printf("B::S(int) called \n"); 15 } 16 }; 17 } 18 19 int main() 20 { 21 { 22 using namespace B; 23 S s; 24 } 25 26 { 27 using namespace A; 28 S s; 29 } 30 }
第23行和第28行,只收到本块的U.D的影响。所以局部简单代码应允许使用U.D.以简化代码:
1 { 2 std::cout << std::hex << 100 << std::endl; 3 } 4 5 { 6 using namespace std; 7 cout << hex << 100 << endl; 8 } 9 10 { 11 using std::cout; 12 using std::hex; 13 using std::endl; 14 cout << hex << 100 << endl; 15 }
哪一个您更喜欢呢?显然在这个场合,没人用using-declare吧?
using namespace xxx;在名字查找时,提供一个类似额外搜索路径的机制。当主路径没有找到名字时,才考虑这个额外搜索路径。例如:
1 #include <iostream> 2 3 namespace Outer{ 4 5 int i=100; 6 7 } 8 9 int main(){ 10 11 int i=20; 12 { 13 using namespace Outer; 14 i=0; 15 } 16 17 std::cout << "Outer::i=" << Outer::i; 18 }
第14行,因为在主搜索路径上i可以找到,就是第11行的int i=20; 因此i没有歧义。主搜索路径,就是一些嵌套的大括号构成的包裹关系路径。
1 #include <iostream> 2 3 namespace Outer{ 4 int i=100; 5 } 6 7 namespace KK{ 8 int i=200; 9 } 10 11 namespace { 12 int i=300; 13 } 14 15 int main(){ 16 using namespace KK; 17 { 18 using namespace Outer; 19 i=0; 20 } 21 }
第19行的i;我们在主搜索路径上人脑搜索一下,就是17~20行为第一层,15~21行为第二层,都找不到i的定义。这时候using namespace引入的辅助搜索路径被考了。会发现有三个名字空间的i;
匿名名字空间的i, KK::i, Outer::i 。编译器会报错,抱怨候选者太多,请程序员明确指示用哪一个。如果using namespace被放到头文件里,还需要人脑做#include展开,所以带给程序员的负担是比较大的。所以,应严格控制using namespace的作用范围。
总结:建议在最内层的块内使用using namespace,就是第18行的样子。谨慎在外层块(第16行)使用,禁止在文件的作用域(包括头文件)使用using namespace