【问题标题】:"using" keyword when defining member functions and non-member functions定义成员函数和非成员函数时的“using”关键字
【发布时间】:2021-05-20 07:03:03
【问题描述】:

“using”关键字在定义成员函数和非成员函数的上下文中是否有不同的效果?下面的示例代码向我表明它可能。

main.cpp

  #include "baz.h"
  int main()
  {
      foo::bar x;
      x.baz();
      foo::foo_non_member();
  }

baz.h

  namespace foo
  {
      class bar
      {
      public:
          bar() = default;
          void baz();
      };

      void foo_non_member();
  };

baz.cpp

  #include "baz.h"
  #include<iostream>

  using namespace foo;
  void bar::baz()
  {
      std::cout << "baz\n";
  }

  namespace foo
  {
  void foo_non_member()
  {
      std::cout << "non-member\n";
  }
  }

以上代码编译运行。

$> g++ main.cpp baz.cpp; ./a.out
baz
non-member

如果我从 baz.cpp 中删除 using namespace foo;,我会收到编译器错误。

$> g++ main.cpp baz.cpp
baz.cpp:5:6: error: ‘bar’ has not been declared
 void bar::baz()

如果我放回 using 语句并将 foo_non_member() 的定义移到 foo 命名空间之外,我会收到链接器错误。

$> g++ main.cpp baz.cpp
/tmp/ccHeSwsZ.o: In function `main':
main.cpp:(.text+0x24): undefined reference to `foo::foo_non_member()'
collect2: error: ld returned 1 exit status

为什么using 关键字在这里似乎对bar::baz()foo_non_member() 没有相同的效果?

【问题讨论】:

  • 它对namespace foo 中声明的每个名称具有完全相同的效果。你在哪里看到不同的效果?你期望什么而不是你得到的结果?
  • foo_non_member() 在显式命名空间块之外定义时,我得到一个链接器错误。当 bar::baz() 在显式命名空间块之外定义时,我没有收到链接器错误。
  • 当一个名字被使用时,它会在一个或多个命名空间中查找。声明或定义名称时,不会在任何地方查找它,而是将其引入到声明它的名称空间中。使用bar,未定义或声明,因此需要查找它。 foo_non_member 正在被定义,所以它没有被查找,它被定义在它所在的位置。
  • "那是因为它显然没有进入链接器阶段。"是的,它确实。如果我将它留在显式命名空间块之外并留在using 语句中,它会编译、链接并运行。
  • 很抱歉变种太多,无论使用或不使用,在命名空间块内或外。哪一个令人惊讶?

标签: c++ namespaces using


【解决方案1】:

对于这部分:

using namespace foo;
void bar::baz()
{
   std::cout << "baz\n";
}

using namespace foo; 用于查找bar:: 部分,因此编译器能够将void bar::baz() 的定义绑定到命名空间foo 中的声明。 如果您删除using namespace foo;,则无法找到bar

如果我将 using 语句放回并将 foo_non_member() 的定义移到 foo 命名空间之外,我会收到链接器错误。

void foo_non_member()
{
   std::cout << "non-member\n";
}

这里的foo_non_memberbar:: 或任何其他(根据规范)没有任何关系,可以让编译器确定此定义与命名空间foo 中的声明相关。

如果using namespace foo; 存在,标准委员会当然可以在规范中添加一些规则,以允许编译器将foo_non_member 定义和声明放在一起,但他们决定不这样做。

这样做的原因可能是因为您会不明确是要在命名空间 foo 之外定义新的 void foo_non_member(),还是要定义 void foo_non_member()foo .

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-06-17
    • 1970-01-01
    • 1970-01-01
    • 2014-07-29
    • 2014-04-16
    • 1970-01-01
    • 2011-06-05
    相关资源
    最近更新 更多