Bingo, Computer Graphics & Game Developer

头文件依赖

当一个头文件被包含的同时也引入了新的依赖, 一旦该头文件被修改, 代码就会被重新编译. 

如果这个头文件又包含了其他头文件, 这些头文件的任何改变都将导致所有包含了该头文件的代码被重新编译. 因此, 我们倾向于减少包含头文件, 尤其是在头文件中包含头文件.

使用前置声明可以显著减少需要包含的头文件数量. 举例说明: 如果头文件中用到类 File, 但不需要访问 File 类的声明, 头文件中只需前置声明 class File; 而无须 #include "file/base/file.h".

不允许访问类的定义的前提下, 我们在一个头文件中能对类 Foo 做哪些操作?

我们可以将数据成员类型声明为 Foo * 或 Foo &.

我们可以将函数参数 / 返回值的类型声明为 Foo (但不能定义实现).

我们可以将静态数据成员的类型声明为 Foo, 因为静态数据成员的定义在类定义之外.

反之, 如果你的类是 Foo 的子类, 或者含有类型为 Foo 的非静态数据成员, 则必须包含 Foo 所在的头文件.


第一个原则应该是,如果可以不包含头文件,那就不要包含了。这时候前置声明可以解决问题。如果使用的仅仅是一个类的指针,没有使用这个类的具体对象(非指针),也没有访问到类的具体成员,那么前置声明就可以了。因为指针这一数据类型的大小是特定的,编译器可以获知。


第二个原则应该是,尽量在CPP文件中包含头文件,而非在头文件中。假设类A的一个成员是是一个指向类B的指针,在类A的头文件中使用了类B的前置声明并便宜成功,那么在A的实现中我们需要访问B的具体成员,因此需要包含头文件,那么我们应该在类A的实现部分(CPP文件)包含类B的头文件而非声明部分(H文件)。