名称空间和作用域可见性问题

Namespaces and scope visibility issue

本文关键字:作用域 可见性问题 空间      更新时间:2023-10-16

我制作了一个头文件sampleheader.h,代码如下:

namespace sample_namespace
{
    int add(int n1,int n2)
    {
        return (n1 + n2);
    }
}
现在我的main.cpp文件是:
#include <iostream>
#include "sampleheader.h"
using namespace std;
int add(int n1, int n2)
{
  return (n1 + n2);
}
int main(void)
{
    using namespace sample_namespace;
    //cout<<add(5,7);
}

如果我留下注释行,项目将在没有警告的情况下构建。这是可以理解的,因为局部add()函数是在全局作用域中定义的,而add()函数是在main()作用域中可见的。因此不会发生名称冲突。

然而,如果我删除注释,我得到以下错误:

"Ambiguous call to overloaded function"

首先,不应该有任何名称冲突,正如我上面解释的那样(如果我是对的)。但是,如果有一个名称冲突,为什么它是由编译器通知只有当我调用函数。这种类型的错误应该在名称冲突时立即显示(如果有的话)。

好吧,你自己解释了。

int add()int sample_namespace::add()都在作用域中时,调用是不明确的。语句add()可以表示它们中的任何一个。

共存的函数不存在冲突,因为一个是int add(),另一个是int sample_namespace::add()。这就是命名空间的全部目的。

你只需要在编写使用它们的代码时弄清楚。如果你摆脱了using namespace指令,总是写显式代码,那么你就不会遇到问题:

#include <iostream>
namespace sample_namespace {
   int add(int n1, int n2) {
      return (n1 + n2);
   }
}
int add(int n1, int n2) {
   return (n1 + n2);
}
int main() {
    std::cout << sample_namespace::add(5,7);
}

(另外,在头文件中定义非内联函数是一个坏主意)

"using namespace"不隐藏其他实现。在这种情况下,它所做的是使它具有二义性。

sample_namespace::add和::add具有相同的签名。由于您没有明确地说明使用哪一个,编译器无法判断。

声明两个函数都是合法且明确的(这就是为什么当你使用该函数时编译器只会报错)。

这样声明两个函数是合法的原因是,通过限定它们,可以明确地调用它们。这就是为什么只有在进行非限定调用时才会得到错误。到目前为止,根本不存在理论问题。

有意地,using namespace X;不应该自己引入歧义错误。这将大大破坏名称空间的目的。通用的using namespace std;引入了许多您自己也可以合理定义的名称。

你不能像那样遮蔽符号,只能遮蔽变量名(这在大多数编译器上是一个警告,即一个坏主意)。using指令在任何意义上都是不精确的,我认为这是大多数人的假设。

using指令将把一个符号导入到作用域中。例如,您可以这样做:

namespace foo {
  using namespace std;
}
foo::string val;

这种做法会导致一些非常恼人的编译器错误。您的简单示例很清楚错误在哪里。如果你试着用几十万行代码来做这件事,你就不会那么高兴了。

我建议你不要养成依赖using指令的习惯。如果必须的话,一次只做一种类型。

using std::string;

基本上,这让你诚实。如果有命名冲突,grep将花费30秒来发现问题在

如果你只花几周时间在你的类型前面输入std::,你会习惯的。

我认为这是因为编译器优化。当你的字符串被注释-他看到,有一些函数,但你不使用它,所以他丢弃它。当他看到这个函数很有用的时候——他想插入函数调用,但是不能选择你想要的那个