头文件(.h)

头文件用来写 类的声明 (包括类的成员的声明和方法声明)、函数原型#define 常数等,但是很少会写出具体的实现和细节。就好比抽象类一样。

头文件很有意思的是,开头和结尾必须按照以下格式:

#ifndef MYCLASS_H
#define MYCLASS_H

// code here

#endif

 

当时我看到这个是极其的不理解和迷茫的,后来阅读了别人的博文才略懂。

首先解释他是干嘛使的,这是防止头文件被重复引用。什么叫被重复引用?就是同一个头文件(.h)在同一个源文件(.cpp)中被include了多次。这种错误常常是因为include嵌套。举个最简单的例子,存在cellphone.h这个头文件引用了#include "huawei.h",之后又有china.cpp这个源文件同时导入了#include "cellphone.h" 和 #include "huawei.h"。此时huawei.h就在一个源文件里引用了两次。

那么,某些时候,只是因为include了两遍,增大了编译器的工作量。如果是小型程序的话还好说,但是大型工程甚至会增长几个小时的编译时间。但是另一些情况,会引起很严重的错误。比如在头文件中定义了全局变量会引起重复定义。

所以就有了我们上面那些看起来乱七八糟的代码,下面开始解释。

#ifndef MYCLASS_H 的意思是 if not define myclass.h,这样看就很好理解了,如果引用这个头文件的源文件不存在myclass.h这个头文件,那么接下行 #define MYCALSS_H, 引入myclass.h。然后就是我们头文件的代码。如果已经有了,直接跳到 #endif。

理论上来说,上面这个片段的MYCLASS_H是可以任意命名的,但是约定俗成的,为了可读性的,我们都把它命名为这个头文件的大写和下划线的形式。如下面这一段代码:

#ifndef HUAWEI_H       // 防止huawei.h被重复引用
#define HUAWEI_H

#include <cmath>       // 引用标准库
#include "honor.h"     // 引用非标准库头文件
...
void Function();         // 全局函数声明
class Mate20{           // 类声明
    public: Mate20();  // 构造函数声明
             ~Mate20(); // 析构函数声明  
    private:
    protected:
};

#endif

 

上面的代码其实已经很好的解释了头文件的作用——声明。可以看见内部的函数和方法仅仅是声明,而都没有写入具体细节。

源文件(.cpp)

源文件主要写实现头文件中已经声明的那些函数的具体代码。需要注意的是,开头必须#include一下实现的头文件,以及要用到的头文件。那么当你需要用到自己写的头文件中的类时,只需要#include进来就行了。

下面举个例子

我首先写一个头文件Pen.h,里面定义了一个Pen类:

#ifndef PEN_H
#define PEN_H
#include <string>
class Pen
{
public:
    Pen(std::string brand);

};

#endif

 

然后我在我的主文件test.cpp中引入了这个头文件:

#include <iostream>
#include "Pen.h"
using namespace std;

Pen::Pen(string brand) {
    cout << "What brand are you looking for?" << endl;
    cout << brand;
}    

int main() {
    Pen pilot("pilot");
    
}

// 输出结果为 
/* What brand are you looking for?
   pilot */

 

结果表明,这样引入是正确的。