作者 | 梁唐
大家好,我是梁唐。
这是EasyC++系列的第43篇,来聊聊头文件的编写。
我们之前做的左右示例都是在一个单独的cpp文件当中完成的,当我们要做一个相对复杂或大型的项目时,我们显然不能把所有代码都写在一个cpp里。这就需要我们拆分代码,但代码按照逻辑划分,写入不同的cpp文件当中。
在我们编译的时候,我们可以将这些cpp文件分别单独编译,最后再连接到一起。这样做的好处是,当我们只修改了某一个文件的时候,可以只用单独编译那一个文件,不会影响其他文件的编译结果。一般来说大型项目,都会使用一下自动化的编译工具,比如make
等,不会手动执行编译过程,但对于这其中的一些细节,还是需要有所了解。
我们来看C++ primer当中提供的一个例子。
现在我们要实现一个将直接坐标转化成极坐标的功能,我们需要定义两个结构体分别表示直角坐标和极坐标,另外还需要实现从直接坐标到极坐标的转化。
显然相对于主体程序而言,这部分代码是独立的,所以我们可以把它们放入一个单独的cpp文件当中。首先要明确的是,main()函数和其他函数都用到了同一个结构体,因此两个cpp文件都需要包含该结构体的声明。显然拷贝代码是很糟糕的选择,比较好的做法是将结构体的声明写在头文件当中,通过#include
语句引入。
这样的话整体的代码就分成三个部分:
在之后面向对象的章节当中, 我们将会经常用到这样的代码结构。
对于头文件当中的内容有严格的限制,由于头文件可能会被多个cpp文件引入,所以我们不能将函数的实现或参数的定义放入头文件当中。因为同一个程序中包含同一个函数的多个定义会引发报错,参数同理。
只有以下内容可以写入头文件当中:
#define
或const
定义的符号常量在同一个文件当中只能引入一个头文件一次,但有的时候由于引用依赖的原因,可能会导致重复引入。比如引入A和B头文件,B头文件中引入了A,导致A被引入两次。
为了解决这个问题,我们可以加入预编译指令#ifndef
,含义是if not defined,判断某定义是否存在。只有当定义不存在时才会直接#ifndef
和#endif
之间的语句:
#ifndef COORDIN_H_
// statements
#endif
一般情况下我们使用#define
创建符号常量:
#define MAXI 4096
但由于这里我们只是用来区分是否引入,所以只需要名称即可:
#ifndef COORDIN_H
#define COORDIN_H
// todo
#endif
这样,当引入一次之后,COORDIN_H
即被定义,那么下次就不会再执行这段代码。最后,我们写出完整的头文件代码:
#ifndef COORDIN_H__
#define COORDIN_H__
struct polar {
double distance, angle;
};
struct rect {
double x, y;
};
polar rect_to_polar(rect xpros);
void show_polar(polar dapos);
#endif