【问题标题】:Using namespaces and includes使用命名空间和包含
【发布时间】:2019-06-20 18:46:57
【问题描述】:

这个问题可能是微不足道的(并且可能是重复的)。

据我了解,一个 C/C++ 头文件(其中包含 using namespace),当被其他源文件使用时,它被复制到该源文件中 #include 指令所在的位置.

此外,鉴于源文件使用了相对大量的包含指令,并且整个标准库可能有几个“重新定义”(仅针对不同的实现)。

这里是主要问题:如果源文件中没有using namespace 语句,我如何知道我当前在源文件中使用了哪些命名空间?

我正在阅读源文件,但我不知道正在使用哪个命名空间。

可以通过使用 ::std::getline() 之类的东西来覆盖命名空间的巧妙性。

如果没有简单的方法来确定命名空间,那么重构这些文件是否公平,例如使用string 将其替换为::std::string

【问题讨论】:

  • 您应该重构这些头文件以删除 using namespace 指令。
  • 从不using namespace ...;放在头文件中。

标签: c++ namespaces include


【解决方案1】:

如果您没有using namespace ... 指令,则说明您没有使用任何命名空间。一般来说,你的代码应该引用标准库中的东西的全名,例如,std::coutstd::get_line()std::string

是的,您可以节省一些输入,但代价是失去清晰度,有时会出现神秘的编译失败,或者更糟糕的是,using namespace std; 会导致运行时失败。之后,您不必将std:: 放在标准库中事物名称的前面:coutget_line()string。 using 指令将这些名称以及一堆您可能不感兴趣的污泥放入全局命名空间中。

如果您使用using namespace std; 之类的内容,它应该出现在源文件中,从不出现在标题中。这样,您可以通过查看文件顶部来判断哪些名称空间已被“使用”。您不必使用指令跟踪所有标头以查找杂散。

【讨论】:

  • 所以从你的意思来看:在源文件中使用命名空间是可以的,而在头文件中应该始终使用显式命名空间(std::xxx)?跨度>
  • @John -- 在源文件中包含using namespace xxx; 比在头文件中更容易。我不会称其中任何一个为“好的”,但对此的看法不同。
  • 感谢您的快速解释。我更喜欢明确并避免使用“使用命名空间”,但是我正在阅读一些资源,我很难弄清楚正在使用哪个命名空间。
  • @John -- re: "which namespace is being used" -- 这可能有点误解。 using 声明将该命名空间中的所有名称放入当前命名空间。通常这意味着进入全局命名空间,就像名称没有在命名空间中定义一样。您可以有多个 using 声明从多个命名空间中提取名称,并且所有这些命名空间中的 所有 名称进入全局命名空间。 using 声明不会取消前面的 using 声明。
【解决方案2】:

using namespace 并不意味着您当前使用这个特定的命名空间。这意味着,对于这个翻译单元,来自这个命名空间的所有类型、变量和函数现在都在你的全局命名空间中。因此,您可能有多个这样的语句。

这就是为什么头文件不应该使用using namespace。没有比在头文件中使用std::string 更简单的方法了,您应该始终对没有using namespaces 的命名空间非常明确。

用过using namespace xxx,恐怕无法发现xxx现在在全局命名空间中。

【讨论】:

    【解决方案3】:

    using namespace 不符合您的预期...

    如果你想在命名空间中放置函数、类或变量,你可以这样做:

    namespace foo
    {
        void f();
    }
    namespace bar
    {
        void f();
    }
    

    这分别在命名空间foobar 中声明了两个函数f。您会在头文件中找到相同的内容;如果没有如上所述指定命名空间,则函数/类/变量位于全局命名空间中。仅此而已。

    using namespace 现在允许您使用命名空间中的函数,而无需明确指定:

    // without:
    foo::f();
    bar::f();
    f();      // unknown!
    
    using namespace foo;
    foo::f(); // still fine...
    bar::f();
    f();      // now you call foo::f
    

    请注意,这是bad practice(链接指的是命名空间std,但同样适用于所有命名空间)。

    这在头文件中更糟糕:无法再次撤消声明的using namespace <whatever> 的效果——所以你将它强加给你的头文件的所有用户,可能会给他们中的一些人带来很大的麻烦。所以请不要在头文件中使用它。

    【讨论】:

      【解决方案4】:

      目前我能想到三种方法:

      使用 IDE:现代开发环境应该能够(可能借助插件)在您编辑时分析您的代码,并告诉您任何标识符的权威限定名称将鼠标悬停在上面。

      当然,如果您不使用 IDE,这不是一个选项,有时甚至 IDE 也可能会混淆并给您错误的信息。

      使用编译器和猜测:如果您已经预知您可能在哪个命名空间中,您可以定义一些对象,通过限定名称引用它,然后查看代码是否编译,如下所示:

      const int Fnord = 1;
      const int* Probe = &::solid::guess::Fnord;
      

      需要注意的是,如果涉及using namespace 或匿名命名空间,它可能会产生误导性结果。

      使用预处理器:大多数编译器都定义了一个预处理器宏,它告诉您使用它的函数的名称,其中可能包括命名空间;例如,在 MSVC 上,__FUNCTION__ 将执行此操作。如果文件包含您知道将执行的函数,您可以让该函数在运行时告诉您其权威限定名称,如下所示:

      int SomeFunction(void)
      {
          printf("%s\n", __FUNCTION__);
      }
      

      如果您不能使用标准输出,您可以将值存储在变量中并使用调试器进行检查。

      如果找不到这样的函数,请尝试使用自身的静态实例定义一个类,并将代码放入构造函数中。

      (不幸的是,我想不出在编译时检查宏值的方法;我想到了static_assert,但它不能在函数内部使用,并且__FUNCTION__ 不能用于外面。)

      虽然宏不是标准化的,并且可能不包括命名空间(或者它可能根本不存在)。例如,在 GCC 上,__FUNCTION__ 只会给您非限定名称,而您必须改用 __PRETTY_FUNCTION__

      (从 C99 和 C++11 开始,确实存在一个标准化的替代方案,__func__,但函数名称的格式未指定,可能包含也可能不包含命名空间。在 GCC 上不包含。)

      【讨论】:

      • 嗯,阅读其他答案,我有一种预感,我可能误解了这个问题。
      猜你喜欢
      • 1970-01-01
      • 2011-02-08
      • 1970-01-01
      • 1970-01-01
      • 2011-11-03
      • 2014-09-06
      • 2011-01-02
      • 1970-01-01
      • 2011-03-01
      相关资源
      最近更新 更多