范围v.s.中定义的变量在该范围内注入的命名空间变量

时间:2018-01-19 18:06:45

标签: c++ scope namespaces

当我运行此代码时,它会显示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;
}

有人能解释那里发生了什么吗?为什么我没有收到任何关于歧义的错误?

1 个答案:

答案 0 :(得分:0)

首先,你的问题本身。在第一个示例中,您使用...

std::cout << ::p;

前置::按特定顺序解析名称空间,从本地名称空间开始。 (见this answer)。因此,它在本地查找p,在外部名称空间(X)中查找然后。因为它在本地找到p,所以它会停止查看。

在第二个示例中,您显式解析您的命名空间:

std::cout << X::p;

因此,没有任何搜索令被打扰。它只是在命名空间p中查找X,否则将失败。

这导致了第二个问题:您似乎混淆了using namespace关键字的用途。这些旨在使您能够使用更简便的方法来解析命名空间,而不是始终使用完全限定的名称(x::p)。

但是,计算机首先仍然查看本地命名空间,然后查找using命名空间。与往常一样,一旦计算机找到命名空间中命名的内容,它就会停止查找

这导致C ++中的一个主要原则:不使用using namespace有例外情况,但您会在工作时接受这些例外情况。问题归结为关于什么命名空间将来自哪个模糊不清,哪些完全你所描述的问题。

例如,假设您在不同的类中定义了名称空间XY,然后您只需要以下内容......

#include "x.hpp"
#include "y.hpp"

using namespace x;
using namespace y;

int main()
{
    std::cout << p << std::endl;
}

p来自哪里?使用命名空间z查看x.hppy. 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,而没有意识到xy也有q,该怎么办?它会解决什么?

这是你永远想要创建的情况!借用Tim Peter的 Python的Zen (尽管是不同的语言,但有些其中的原则在大多数语言中都是正确的)...

  

明确比隐含更好。

那么,我们怎么能把它写得更不那么狡猾 - 摇摇欲坠的时间 - wimey?

  1. 放弃 using namespace。你唯一一次触摸这个就是你在一个命名空间中使用的东西,而在其他任何地方使用 nothing 。 (您会注意到大多数C ++程序员甚至不会using namespace std;

  2. 在您使用的任何内容中使用完全限定名称。例如,x::p

  3. 如果您使用 lot ,请使用文件顶部的using x::p命令。这会将p解析为namespace x,而不会混淆其他所有内容。

  4. 简而言之,您应该能够一目了然地知道所有来自哪个命名空间。 从不创造歧义和隐式解决的情况;只有这样的错误和痛苦。