当我运行此代码时,它会显示6
...
#include <iostream>
namespace X {
int p = 5;
}
using namespace X;
int p = 6;
int main()
{
std::cout << ::p;
return 0;
}
但是,当我运行此代码时,它会显示5
...
#include <iostream>
namespace Y {
int p = 16;
}
namespace X {
int p = 5;
using namespace X;
}
int main()
{
std::cout << X::p;
return 0;
}
有人能解释那里发生了什么吗?为什么我没有收到任何关于歧义的错误?
答案 0 :(得分:0)
首先,你的问题本身。在第一个示例中,您使用...
std::cout << ::p;
前置::
按特定顺序解析名称空间,从本地名称空间开始。 (见this answer)。因此,它在本地查找p
,在外部名称空间(X
)中查找然后。因为它在本地找到p
,所以它会停止查看。
在第二个示例中,您显式解析您的命名空间:
std::cout << X::p;
因此,没有任何搜索令被打扰。它只是在命名空间p
中查找X
,否则将失败。
这导致了第二个问题:您似乎混淆了using namespace
关键字的用途。这些旨在使您能够使用更简便的方法来解析命名空间,而不是始终使用完全限定的名称(x::p
)。
但是,计算机首先仍然查看本地命名空间,然后查找using
命名空间。与往常一样,一旦计算机找到命名空间中命名的内容,它就会停止查找。
这导致C ++中的一个主要原则:不使用using namespace
!有例外情况,但您会在工作时接受这些例外情况。问题归结为关于什么命名空间将来自哪个模糊不清,哪些完全你所描述的问题。
例如,假设您在不同的类中定义了名称空间X
和Y
,然后您只需要以下内容......
#include "x.hpp"
#include "y.hpp"
using namespace x;
using namespace y;
int main()
{
std::cout << p << std::endl;
}
p
来自哪里?使用命名空间z查看x.hpp
和y.
hpp , you see that BOTH have
p , so which one is used? And then, what if you add
; above them? Now you have to check if
z has
p`。哎呀!
(有关命名空间解析的更多信息,请参阅this answer。)
值得注意的是,就编译器/链接器而言, 没有歧义。它有一个隐含的解决方案来处理它。模糊不清就在编码器上。
更糟糕的是,如果您在本地定义q
,而没有意识到x
或y
也有q
,该怎么办?它会解决什么?
这是你永远想要创建的情况!借用Tim Peter的 Python的Zen (尽管是不同的语言,但有些其中的原则在大多数语言中都是正确的)...
明确比隐含更好。
那么,我们怎么能把它写得更不那么狡猾 - 摇摇欲坠的时间 - wimey?
放弃 using namespace
。你唯一一次触摸这个就是你在一个命名空间中使用束的东西,而在其他任何地方使用 nothing 。 (您会注意到大多数C ++程序员甚至不会using namespace std;
)
在您使用的任何内容中使用完全限定名称。例如,x::p
。
如果您使用 lot ,请使用文件顶部的using x::p
命令。这会将p
解析为namespace x
,而不会混淆其他所有内容。
简而言之,您应该能够一目了然地知道所有来自哪个命名空间。 从不创造歧义和隐式解决的情况;只有这样的错误和痛苦。