头文件通常包含那些只能被定义一次的实体。
如:类、const 、constexpr变量

注意:
1、头文件一旦改变,相关的源文件必须重新编译以获取更新过的声明。
2、头文件不应包含using声明
(因为头文件的内容会拷贝到所用引用它的文件中去,如果头文件里有某个using声明,那么每个使用该头文件的文件就都会有这个声明,对于某些程序来说,由于不经意间包含了一些名字,反而可能产生始料未及的名字冲突。)

预处理器(preprocessor)

确保头文件多次包含仍能安全工作的常用技术是预处理器,它由c++ 语言从 c 语言继承而来。
预处理器是编译之前执行的一段程序,可以部分地改变所写的程序。

头文件保护符(header guard)依赖于预处理变量。
预处理变量有两种状态:已定义,未定义。(预处理变量无视c++语言中关于作用域的规则。)

注意:
整个程序中的预处理变量包括同文件保护符必须唯一。通常做法是基于头文件中类的名字来构建保护符的名字,以确保唯一性。
一般把预处理变量的名称全部大写(为了避免与程序中的其他实体发生名字冲突)。

#define 指令把一个名字设定为预处理变量

下面这两个指令是检查某个预处理器变量是否已经定义
#ifdef 当变量已定义时为真(个人理解:if def 如果定义 )
#ifndef 当变量未定义时为真 (个人理解:if not def 如果未定义)

一旦检查结果为真,则执行后续操作直至遇到#endif 指令为止。

预处理变量命名规则

在理论上来说可以是自由命名的,但每个头文件的这个“标识”都应该是唯一的。
标识的命名规则一般是头文件名全大写,前后加下划线,并把文件名中的“.”也变成下划线。
如:stdio.h

  1. #ifndef _STDIO_H_
  2. #define _STDIO_H_
  3. ......
  4. #endif

执行过程理解

第一次包含Salesdata.h 时,#ifndef 的检查结果为真,与初期将顺序执行后面的操作,直至遇到#endif 为止。
此时,预处理变量_SALES_DATA_H
的值将变为已定义,而且Sales_data.h 也会被拷贝到我们冲虚中来。

再一次包含Sales_data.h 时,#ifndef 的检查结果为假,编译器会忽略 #ifndef 到 #endif 之间的部分。