【问题标题】:why should i include the header file <iostream> after using the namespace std?为什么在使用命名空间 std 后要包含头文件 <iostream>?
【发布时间】:2014-11-23 01:48:22
【问题描述】:

既然命名空间std已经有包含函数定义的c++库(如果我是对的),那我们为什么要在它上面包含头文件呢??由于命名空间 std 包含 c++ 标准库,我认为没有理由单独包含它的声明。

【问题讨论】:

  • 不太确定您是在问“为什么我们需要命名空间和头文件”,还是“为什么#include &lt;iostream&gt;using namespace std; 的顺序不同?
  • 除非您的程序要求包括在 DOS 上工作,否则您永远不应包含 iostream.h
  • 说您正在使用命名空间与说您可以访问该命名空间中包含的所有类绝不相同。所以,本质上你是在问为什么需要包含头文件来访问那里声明的类?
  • iostream.h 看起来很奇怪。目前的标准实际上是指#include &lt;iostream&gt;
  • @CareyGregory:在 Unix 中你可能没有iostream.h - 注意iostreamiostream.h 之间的区别。

标签: c++ std header-files iostream


【解决方案1】:

当您执行#include &lt;iostream&gt; 时,它会导致一组类和其他内容包含在您的源文件中。对于 iostream 和大多数标准库头文件,它们将这些内容放在名为 std 的命名空间中。

所以#include &lt;iostream&gt; 的代码看起来像这样:

namespace std { 
    class cin  { ... };
    class cout { ... };
    class cerr { ... };
    class clog { ... };
    ...
}

所以此时,您可以编写如下所示的程序:

#include <iostream>

int main() {
    std::cout << "hello\n";
    return 0;
}

现在,有些人觉得std::cout 太冗长了。所以他们这样做了:

#include <iostream>
using namespace std;

int main() {
    cout << "hello\n";
    return 0;
}

我个人建议不要这样做,如果你真的觉得std::cout 过于冗长,那么我建议你使用更小的using 语句。

#include <iostream>
using std::cout;

int main() {
    cout << "hello\n";
    return 0;
}

如果您想知道为什么我会推荐反对 using namespace std,那么我会将您转发到 stackoverflow 上的以下另外两个帖子:

【讨论】:

  • 所以“ using namespace std; ”然后是“ cout ”文件中的 cout 吗?即使不包括 文件?因为在 文件中,这些 cout、cin 被放置在命名空间 std 中,所以我们可以只使用 std 命名空间而省略标头包含吗?
  • @ManojBharadwaj:不。许多不同的头文件会将内容放在该名称空间中。 using 命令并不隐式知道是哪个标头。
  • 但是在单个命名空间中只有 1 个同名的对象,这还不够吗?
  • 但是编译器如何知道cin 是什么或做什么?这来自 iostream 的内容。编译器本身不知道这个文件包含什么,或者cin 来自iostream。这是运行时库的一部分,而不是编译器本身,因此它必须由编译器编译,您的程序才能使用它。
【解决方案2】:

编译器本身没有任何命名空间(无论是std 还是其他命名空间)中的事物的定义。那就是源文件和头文件的作用。

using namespace std; 告诉编译器的是“如果在当前命名空间中找不到某个名称,请同时查看 std 命名空间”。

#include &lt;iostream&gt; 告诉编译器的是您希望将名为 iostream 的标头的内容包含在您的源代码中。这将为编译器提供代码来执行cincout 和许多其他相关功能。该文件的内容声明为namespace std { ... all the stuff goes here ... }

命名空间的使用使在namespace math; 工作的其他人不必担心“嗯,我现在该怎么办,我需要一个入口数量计数器,我们称之为cin - 但请稍等,它曾经在任何地方使用过吗?”。

这可能不是最好的例子,但在大型项目中,跟踪事物及其名称变得越来越困难。而且 C++ 是一种用于包含数百万行代码的大型项目的语言——现在它开始变得难以记住你是否使用过特定的名称。命名空间确保您不必担心特定命名空间之外的问题。

(哦,在我的代码中,我倾向于不使用using namespace std;,而是写std::cout &lt;&lt; "Hello, World!" &lt;&lt; std::endl; - 这有助于明确我在这里使用的coutstd 之一,并且不是别的。当您有多个具有相似内容的命名空间时,这特别有用,例如在我自己的编译器中,我的编译器具有它的功能,std 命名空间提供一些东西,llvm 编译器的东西 - 如果我如果将using namespace llvm; 粘贴在代码的开头,则很难跟踪Type* p = ...; 是来自LLVM 还是我自己代码的某些部分。)

【讨论】:

    【解决方案3】:

    ...为什么我们要在上面包含头文件???

    是的,这里有一些很大的混乱。

    命名空间

    命名空间是一种对函数名称等符号进行分类或分组的方法。

    命名空间旨在防止不同软件组件(例如库)之间的名称冲突。

    作为标准语言一部分的函数被分组在命名空间std 下。

    C++ 语言提供语句来减少使用命名空间时的输入量。其中之一是using 声明。

    标头(包含)文件

    当您编写程序时,编译器不需要自动包含所有符号定义,例如函数声明。您需要告诉它您打算使用哪些功能。

    例如,我可以在不使用 algorithm 组中的 sortadvance 函数的情况下编写程序。因此我不会包含头文件algorithm

    C++ 语言被设计为“使用你需要的东西”,换句话说,我们可以通过只包含我们需要的功能来创建小程序。

    其他平台

    顺便说一句,除了您使用的平台之外,还有许多其他平台。

    某些平台需要适应较小的内存区域,并且可能没有键盘或显示器(例如嵌入式控制器)。

    请记住,C++ 被定义为支持从小型且受限的平台到大型且几乎不受约束的系统。

    因此要求“仅包含您需要的”主题。

    总结

    总而言之,由于 C++ 语言不会自动、神奇地提供整个库的定义,包括模板库,因此您需要告诉编译器您要使用哪些函数组。这允许更快的编译,因为只指定了所需的头文件。

    注意:一些商店和图书馆用品喜欢使用 Monolith 包含系统。这意味着他们有一个包含整个库的包含文件,无论您使用一个函数还是多个函数。 windows.h 是一个典型的例子。一个不利因素是,当一个头文件更改时,所有内容都需要重新构建。使用分离的包含文件,只需要重建包含更改的头文件的组件。

    【讨论】:

      【解决方案4】:

      预处理指令#include 的使用与c++ 本身一样古老。而且它不会很快消失。在 C++ 命名空间中不会将任何内容导入您的程序,它只是定义了特定头文件函数的范围。因此,两者都是必需的。 Click here了解为什么要使用命名空间。

      【讨论】:

        【解决方案5】:

        您的问题是:namespace std 具有 iostream 库的所有函数/类的定义。所以只需使用using namespace std 就足以调用或使用coutiostream 库的所有其他功能。为什么我们必须使用#include &lt;iostream&gt; 行?这似乎是多余的。

        我们大致可以认为iostream 库有两个文件:头文件和实现/源文件。这两个文件有一个名为std 的命名空间。头文件仅包含 iostream 库将使用的类或函数或变量的声明或前向声明,这些声明或前向声明位于 std 命名空间下。实现文件包含类或函数或变量的实际实现,这些实现位于std 命名空间下;此文件也称为源文件。

        因此,如果您在main.cpp 文件中仅使用using namespace std 而没有#include &lt;iostream&gt;,编译器将在您的main.cpp 文件中搜索std 命名空间,但它不在这里。你会得到编译器错误。

        现在,如果您在main.cpp 中包含此#include &lt;iostream&gt; 行,预处理器将转到iostream 的头文件并将std 命名空间及其代码复制到我们的main.cpp 中。链接器会将iostream 的预编译(因为iostream 是SLT,因此它带有带有预编译的编译器)源/实现文件链接到您的main.cpp。现在要使用位于main.cpp 中的std 命名空间下的iostream 的函数或变量,我们必须使用范围解析运算符(::) 来告诉编译器coutcin 和@987654350 的其他功能@ 位于 std 命名空间。因此我们简单地写成这样:std::cin,和std::cout

        现在输入 std:: 对某些人来说似乎是多余的,所以他们通过使用 using namespace std 告诉编译器“嘿编译器,如果您在全局/当前命名空间中找不到任何变量/函数/类,请查看 @ 987654356@ 命名空间。”虽然这不是最佳实践,但这是另一个要讨论的话题。因此,您假设 std 命名空间包含所有 SLT 的 C++ 函数/类/变量的所有定义在大多数情况下是不正确的,但 std 命名空间仅包含来自 STL 的声明是正确的假设。

        这是一个如何将iostream libray 添加到我们的代码文件中的虚拟实现: iostream.h:

        // This is header file that only contains the
        // functions declarations.
        namespace std_dum
        {
            int add(int x, int y);
        
            int mult(int x, int y);
        }
        

        iostream_dum.cpp:

        // This is source file of iostream_dum.h header
        // which contains the implementation of functions.
        
        #include "iostream_dum.h"
        
        namespace std_dum
        {
        
            int add(int x, int y)
            {
                return x + y;
            }
        
            int mult(int x, int y)
            {
                return x * y; 
            }
        
        }
        

        main.cpp

        #include <iostream>
        #include "iostream_dum.h"
        
        int main()
        {
            std::cout << std_dum::add(100, 200) << '\n';
            std::cout << std_dum::mult(100, 200) << '\n';
        
            return 0;
        }
        

        要查看预处理后我们的main.cpp 文件会发生什么,请运行以下命令:g++ -E main.cpp iostream_dum.cpp

        我们的main.cpp大概是这样的:

        namespace std_dum
        {
            int add(int x, int y);
        
            int mult(int x, int y);
        }
        
        int main()
        {
         std::cout << std_dum::add(100, 200) << '\n';
         std::cout << std_dum::mult(100, 200) << '\n';
        
         return 0;
        }
        
        namespace std_dum
        {
        
            int add(int x, int y)
            {
                return x + y;
            }
        
            int mult(int x, int y)
            {
                return x * y;
            }
        
         }
        

        为了清楚起见,我丢弃了预处理器从#include &lt;iostream&gt;复制的所有代码。

        现在应该很清楚了。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2015-10-28
          • 1970-01-01
          • 2013-05-10
          • 1970-01-01
          • 2012-09-19
          • 2015-05-21
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多