头文件的知识比较有限,应该完全掌握
理解#include#include的定位是模块机制
#include就是单纯的文本复制替换,非常简单
python的import有更复杂的语义,解释执行模块,模块缓存
C++20的import也是朝着模块语义去的
但是我们现在是C++17,大部分C++代码仍然只有#include
#include能满足大部分模块机制的需要
编译过程中,头文件被复制到源文件中,每个源文件被当作一个编译单元进行编译
所以一个编译target中,其实只有源文件,没有头文件
inline头文件此外,#include "A.inl"是Zelo中常用的一种方法
inl=inline,#include就是inline过程
inl并不会影响编译结果,但是可以拆分文件
常用的有两个用途:
- 分离出模板成员的实现,这样.h只有声明
- 分离出生成的C++代码,将手写代码和生成代码分开
理解声明和定义
这是C就有的概念,和编译过程有关,《游戏引擎》C++一章节有讲,这里不重复了
C的One Definition规则,只运行一个定义
可以有很多声明,声明和定义的类型应该是一致的
头文件应该只有声明,没有定义
但是用户拿到头文件的声明,还是没法编译(广义的编译),因为链接过程需要定义,或者说是完整的实体
所以要在源文件#include
前向声明前向声明是一种用法,主要的作用是解耦头文件依赖
用class A前向声明,替代#include A,可以减少对A.h的依赖,这样A.h修改时,就不需要重新编译本文件
在两个类循环依赖时,前向声明是必要的,比如Entity和Component
Zelo在不影响可读性的情况下会尽量使用前向声明,减少头文件依赖
LuaBind_XXX里会用函数的前向声明,因为LuaBind就是一堆源文件,只有LuaBind_XXX函数,如果每个文件配一个头文件,很臃肿
前向声明的缺点
- 模板只能用#include
- #include对重构和IDE友好
IDE确定#include的符号实体,但是不确定前向声明的符号(没有实体)



