zoukankan      html  css  js  c++  java
  • headerfiles

    在程序中,.cpp扩展的文件并不是唯一一种常见的文件。另一种文件称为头文件,有时被称为include file。都文件基本都有一个.h扩展名。头文件的目的是将其它文件要用到的声明整合到一起。

    标准库头文件的使用

    看一下下面的程序:

       1: #include <iostream>
       2: int main()
       3: {
       4:     using namespace std;
       5:     cout << "Hello, world!" << endl;
       6:     return 0;
       7: }

    这个程序使用cout将Hello, world!输出到控制台的屏幕中。但是,你的程序从没有定义cout,编译器如何知道cout是什么呢?答案是,cout在头文件iostream中已经声明过了。当我们使用#include <iostream>时,我们已经告诉编译器定位然后读取头文件iostream中的所有声明。

    记住头文件中往往只包含了声明。它们并不定义具体的实现,而且你已经知道如果连接过程中,不能够找到你使用的东西的定义,你的程序在链接时将会出错。那么如果cout不是在iostream头文件中定义的,它实际又在哪里实现的呢?它是在运行库支持下实现的,在链接的过程中运行库会自动的链接到你的程序。

    库是能够反复被很多程序使用的代码的集合。更据代表性的来讲,一个库包含了头文件,头文件中包含了库里的任何能够被用户使用的东西的声明,预编译对象将所哟逇代码用机器码进行了实现。在windows中库的扩展名通常是 .lib 或 .dll,在Unix中,通常为 .a 或 .so。为什么要进行预处理呢。首先,由于库很少改变,它们通常不需要反复编译。每次都编译它们会浪费很多时间。其次,由于预编译对象是机器语言,它阻止人改变代码,出于对知识产权的保护,对于那些不想让别人知道源代码的人来说是很重要的。

    编写你自己的头文件

    现在让我们回到前面讨论过的问题。我们有两个文件add.cpp和main.cpp

    add.cpp:

    1  int add(int x, int y)
    2  {
    3      return x + y;
    4  }

    main.cpp

       1: #include <iostream>
       2:  
       3: int add(int x, int y); // forward declaration using function prototype
       4:  
       5: int main()
       6: {
       7:     using namespace std;
       8:     cout << "The sum of 3 and 4 is " << add(3, 4) << endl;
       9:     return 0;
      10: }

    这里使用了前置声明,编译时编译器能够知道使用的add具体是什么。前面提到过,在每次使用函数前写前置声明是一件很烦人的事情。

    头文件能够较少我们这方面的压力。一个头文件只需要写一次,就能够在很多源文件中使用。这也有助于使得函数原型改变时造成的改动减小(如,增加一个参数)。

    书写我们的头文件是相当简单的。头文件包含两部分。第一部分是头文件保护,在预处理器一节中会详细介绍。第二部分是实际的内容,用来声明我们想要其他源文件能够看到的函数。我们的头文件的扩展名也是.h。

    add.h:

       1: #ifndef ADD_H
       2: #define ADD_H
       3:  
       4: int add(int x, int y); // function prototype for add.h
       5:  
       6: #endif

    为了main中能够使用头文件,必须将它包含进去。下面是一个新的main.cpp:

       1: #include <iostream>
       2: #include "add.h" // this brings in the declaration for add()
       3:  
       4: int main()
       5: {
       6:     using namespace std;
       7:     cout << "The sum of 3 and 4 is " << add(3, 4) << endl;
       8:     return 0;
       9: }

    当编译器读到#include "add.h"这一行的时候,它将add.h中的内容都复制到当前的文件中。因为我们的add.h中包含了函数add的原型,作为函数add的前置声明。

    因此,我们的程序能够正确的编译和链接。

    你也许会很好奇为什么对于iostream我们使用了尖括号,对于add.h我们使用了双引号。原因是尖括号告诉编译器我们包含的头文件是编译器包含的。双引号告诉编译器头文件是我们提供的,这告诉编译器首先在当前包含源文件的文件夹中寻找头文件。

    规则:包含与编译器结合在一个的头文件使用尖括号。包含其他的头文件使用双引号。

    另一个通常问的问题是“为什么iostream没有.h扩展名”。因为iostream.h和iostream是不同的,要解释它需要一个简短的历史背景。

    当C++最初被创建的时候,标准运行库中的所有文件都是以.h结尾的。一直都是始终如一的,cout和cin的原来的版本也都存在于iostream.h中。当语言被ANSI委员会标准化后,它们决定将所有运行库的函数移到std命名空间下(这是一个好想法)。但是,又引起了一个问题:如果把所有的函数移到std命名空间,以前的程序都将不能运行。

    为了解决这么问题,一系列新的没有.h后缀的具有相同名称的头文件被推荐使用。新的头文件中的所有的内容都是在std命名空间内的。这样,包含#include <iostream.h> 旧的程序不必要被重写,新的程序可以使用#include <iostream>。

    当你使用标准库的头文件的时候确保你没有使用.h扩展的头文件。否则,你将会使用一个被弃用的不再将被支持的版本。

    作为边注,标准库中的很多头文件没有不具有不带.h的版本,只有带.h 的版本。对于这些文件,使用.h的版本是可以的。很多这类库向后兼容标准C程序,C程序不支持命名空间。当你写你的头文件的时候,它们通常是以.h结尾的,你没有必要将你的代码放到std命名空间中。

    规则: 如果库中存在,就是用使用不带.h的版本,通过std命名空间访问功能。如果不存在不带.h扩展名的版本,或是你自己建立的头文件,使用.h的版本。

     

     

  • 相关阅读:
    heapq of python
    array of python
    Unittest of Python
    事件驱动型工作流 vs 引擎型工作流
    airflow
    WPF 调试触发器
    WPF 使用Popup和TreeView实现树状下拉框
    Oracle : ORA 00933: SQL command not properly ended
    PostgreSQL && PostGIS
    基于ArcGIS开发3D立方体空间关系判断
  • 原文地址:https://www.cnblogs.com/tk091/p/2455149.html
Copyright © 2011-2022 走看看