C++程序员都知道不要用或尽量少用using指示,而是用using声明。两个原因:
(1)这个原因是大部分人都知道的:using 声明能够明确的只引入你要引入的命名空间名字,而using指示则会把命名空间的所有名字都引入到局部作用域中;
(2)另外一个原因是using指示的作用域问题相对using声明复杂很多。
C++ primer中对using声明引入的名字的作用域规则说明是:
从using声明的地方开始,一直到using声明所在的作用域结束为止,using声明的名字的作用域与using声明语句本身的作用域一致。
而using指示引入的名字的作用域就比较复杂了,这也是这一篇文章要讨论的重点。
二.using指示的作用域问题
C++ primer中对此的说明为:它具有将命名空间成员提升到包含命名空间本身和using指示的最近作用域的能力。
刚看到这一句的时候很迷惑,然后又去翻了原著中对这段的描述:
A using directive does not declare local aliases for the namespace member names. Rather, it has the effect of lifting the namespace members into the nearest scope that contains both the namespace itself and the using directive.
其中的the nearest scope应该是指命名空间所在的最近的外层作用域或using指示所在的最近的外层作用域(两者取其大)。
书中举的例子并不能很好的说明这一点。所以我自己写了几个例子来测试这个问题:
test1:
namespace test1{
int i = 1; //位置1
namespace my{
namespace my1{
int i = 2; //位置2
}
}
namespace my{
void func()
{
using namespace my1;
std::cout << "hello:" << i;
}
}
}
调用test1::my::func()打印出来的i的值为2,即为位置2中定义的i。说明此时using指示使得作用域my1中的成员的作用域提升到作用域my中。
test2:
namespace test2{
int i = 1; //位置1
namespace my{
namespace my1{
int i = 2; //位置2
}
}
using namespace my::my1;
namespace my{
void func()
{
std::cout << "hello:" << i;
}
}
}
此时编译时会有错误,提示i为不明确的符号。这是因为此时using指示将my::my1::i的作用域提升到test2中,所以和位置1定义的i产生了二义性。将func()中的语句改成下面的例子就可以编译通过了:
std::cout << "hello:" << my1::i;
test3:
namespace test3{
int i = 1; //位置1
namespace my{
namespace my1{
int i = 2; //位置2
}
}
}
using namespace test3::my::my1;
namespace test3{
namespace my{
void func()
{
std::cout << "hello:" << i;
}
}
}
此时调用test3::my::func()打印出来的值为1,即为位置1定义的i,这是因为此时using指示已经将test3::my::my1提升到全局区域了,所以在没有限定时位置1的test3::i隐藏了全局区域的i
test4:
namespace test4{
int i; //位置1
namespace my{
namespace my1{
int i = 2; //位置2
}
}
namespace myfun{
void func()
{
using namespace my::my1;
std::cout << "hello:" << i;
}
}
}
这个例子也会让func中访问的i产生二义性,原因是此时的using指示让my::my1::i提升到了test4的作用域中。可以如下将func()修改:
std::cout << "hello:" << my::my1::i;
或:
std::cout << "hello:" << test4::i;