【问题标题】:using namespace std; in a header file使用命名空间标准;在头文件中
【发布时间】:2013-01-12 14:29:43
【问题描述】:

所以,我在规范文件中有以下内容

#include <string>
#include <fstream>
using namespace std:

class MyStuff
{
    private:

    string name;
    fstream file;
    // other stuff

    public:
    void setName(string);
}

我在实现文件里也有

#include "MyStuff.h"
using namespace std;

void MyStuff::setName(string name);
{
     name = name
}

在我的程序文件中...

#include <iostream>
#include <string>
using namespace std;

void main()
{
     string name;
     MyStuff Stuff;

     cout << "Enter Your Name: ";
     getline(cin, name);

     Stuff.setName(name);
}

我正在收集应用“使用命名空间 std;”在头文件中是禁止的,完全符合条件是“更好”的做法;比如std::cout &lt;&lt; stuff &lt;&lt; endl;

据我了解,要使用字符串,它必须具有 std 命名空间。这是真的吗?

如果是这样,在头文件中,更“纯粹/干净”的做法是......

#include <string>

class MyStuff
{
     std::string name;
}

而且,据我目前了解,使用命名空间 std;在所有三个文件(规范、实现和程序)中,基本上将三个命名空间叠加在一起,所以如果我在每个文件中分别声明 string name;,编译器将不知道哪个到哪个。这是真的吗?

我一般都明白,清楚是一件“好”的事情,但我对具体如何做有点不清楚,我最感兴趣的是更深层次的“为什么”,这是这一切的基础。

所以我的直接问题是,在我提供的示例中,为编译器和行业“标准”描述函数的“最清晰”方式是什么?而且,您能否将我引导到更清楚地描述命名空间的推理和实际实现的资源。

【问题讨论】:

    标签: c++ class namespaces header-files


    【解决方案1】:

    using namespace std; 的多个实例不会导致任何歧义。问题是该语句将std 的所有名称/类型/函数导入到您的命名空间中,现在如果您想命名一个类string,例如,您将遇到麻烦。删除、擦除等功能更可能发生这种情况。

    在标头中使用它会更糟,因为它会传播到该标头的所有.cpps,而没有人意识到包含它。在.cpp 中使用它至少需要一个有意识的选择。

    更完整的解释可以在Why is "using namespace std" considered bad practice?获得

    一个可能由此导致的问题示例可以在How to use an iterator? 中找到,其中 OP 定义了一个函数 distance,并不断得到错误的答案。 另一个例子Confusion about pointers and references in C++

    【讨论】:

    • 为什么 using namespace std 的多个实例不会引起歧义?
    【解决方案2】:

    命名空间使用是为了您的方便,而不是让您强加于他人:切勿在#include 指令之前编写 using 声明或 using 指令。

    推论:在头文件中,不要写命名空间级别的 using 指令或 using 声明;相反,明确命名空间限定所有名称。 (第二条规则从第一条开始,因为标头永远无法知道其他标头#includes 可能出现在它们之后。)

    我一般都明白,清楚是一件“好事”,我是 但是关于如何的具体情况有点不清楚,我最 对这一切背后的更深层次的“为什么”感兴趣。

    下面的代码 sn-ps 反映了为什么在头文件中使用using namespace 是不好的:

    // snippet 1
    namespace A {
     int f(double);
    }
    
    // snippet 2
    namespace B {  
        using A::f;
        void g();
    }
    
    // snippet 3
    namespace A {
        int f(int);
    }
    
    // snippet 4
    void B::g() {
        f(1);   // which overload is called?
    }
    

    所以在你的例子中,这个更好:

    #include <string>
    
    class MyStuff
    {
        std::string name;
    };
    

    推荐书:C++ Coding Standards: 101 Rules, Guidelines, and Best Practices

    和链接:Google C++ coding guide

    【讨论】:

      【解决方案3】:

      假设我自己声明了一个类string。因为我是一个懒惰的流浪汉,所以我在全局命名空间中这样做。

      // Solar's stuff
      class string
      {
          public:
              string();
              // ...
      };
      

      一段时间后,我意识到重用一些您的代码将有益于我的项目。感谢您将其开源,我可以这样做:

      #include <solarstuff.hpp>
      #include <phoenixstuff.hpp>
      
      string foo;
      

      但是突然编译器不再喜欢我了。因为有一个::string(我的班级)和另一个::string(标准的,包含在您的标题中并使用using namespace std;带入全局命名空间),所以会有各种各样的痛苦有。

      更糟糕的是,这个问题会通过包含 my 标头的每个文件(包括您的标头,...您明白了。)

      是的,我知道,在这个例子中,我也应该责备我没有在我自己的命名空间中保护我自己的类,但那是我临时想出的。

      命名空间的存在是为了避免标识符冲突。您的标头不仅将MyStuff 引入全局命名空间,而且将stringfstream 中的每个 标识符引入。很可能它们中的大多数都不是我们俩真正需要的,那么为什么要将它们拖到全球范围内,污染环境呢?

      补充:从维护编码器/调试器的角度来看,foo::MyStuffMyStuff 方便十倍,命名空间在其他地方(可能甚至不是同一个源文件),因为您可以在代码中需要它的位置获得命名空间信息。

      【讨论】:

      • 让我看看我有没有得到这个...声明的被放入全局命名空间,如果有另一个同名的函数,就会发生冲突,从而“污染”程序的歧义。
      • @MichaelPhoenix:using namespace std; 的含义是“使来自std:: 命名空间的所有标识符在全局命名空间中也可用”。它确实 not 意味着该语句之后的任何内容都“放入”该名称空间(您需要 namespace std { } - 不,不要这样做,std:: 是标准的,但你明白我的意思)。
      • @MichaelPhoenix:但是全局命名空间是每个人都在使用的东西,比如int x;foo()using 在头文件中的效果是,之前完全正常的代码突然无法正确编译,因为现在它与标准(或其他第三方)头文件中声明的标识符发生冲突。这不应该发生:所有第三方代码(您的库代码也是如此)都应该在命名空间中。全局命名空间是为写int main()的人保留的。
      猜你喜欢
      • 1970-01-01
      • 2021-10-12
      • 2011-08-29
      • 1970-01-01
      • 2015-08-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多