头文件只声明、源文件只定义是C++多文件项目核心规范。头文件含类/函数声明、extern变量、类型别名等,须加保护;源文件实现对应定义,先包含自身头文件,避免using namespace和循环包含。

头文件(.h 或 .hpp)只负责声明,源文件(.cpp)只负责定义——这是 C++ 多文件项目组织最核心的规范。分离得当,才能避免重复定义、链接错误、编译缓慢和维护困难。
头文件里写什么?
头文件是“接口说明书”,对外暴露你希望别人用的东西,不暴露实现细节。
- 类声明(class 名称 { ... };),不含成员函数体(除非是内联或模板)
- 函数声明(int add(int a, int b);),不写函数体
- extern 全局变量声明(extern const double PI;)
- 类型别名(using、typedef)、枚举、结构体纯声明
- 必须加头文件保护(#pragma once 或 #ifndef / #define / #endif)
- 尽量少 include 其他头文件;必要时优先用前置声明(class X;)替代 #include "X.h"
源文件里写什么?
源文件是“实现说明书”,把头文件里声明的东西真正做出来,且一个定义只出现一次。
- #include 对应的头文件(如 Foo.cpp → #include "Foo.h"),通常放在第一行
- 包含其他所需头文件(标准库、第三方、项目内依赖),按层级分组并排序(例如:自身头→系统头→项目头)
- 实现类成员函数(可写在类外,如 void Foo::bar() { ... })
- 定义非 inline 全局函数和 static/const 变量
- 不写 using namespace xxx(尤其不在头文件里!)
常见错误与规避方法
很多链接错误和编译失败都源于分离不当。
立即学习“C++免费学习笔记(深入)”;
- 定义写在头文件里又没加 inline/constexpr → 多个 cpp 包含后触发 ODR(One Definition Rule)违规。解决:移到 .cpp,或加 inline,或改 constexpr
- 头文件循环包含 → A.h #include B.h,B.h 又 #include A.h。解决:用前置声明替代部分 #include,检查逻辑耦合是否过重
- 忘记头文件保护 → 同一文件被多次展开,导致重定义。所有 .h 必须有 #pragma once 或宏卫士
- 在头文件中 using namespace std; → 污染包含该头的所有翻译单元,易引发命名冲突。一律禁止
- 源文件没 #include 自己的头 → 编译器无法验证声明与定义是否一致。每个 .cpp 都应先 #include 对应 .h
目录结构建议(中小项目)
清晰的物理结构能强化逻辑分离意识。
- /include/ —— 所有对外头文件(安装或第三方可见),如 include/math/Vec2.h
- /src/ —— 所有 .cpp 实现,按模块组织,如 src/math/Vec2.cpp
- /src/main.cpp —— 入口单独放顶层
- /CMakeLists.txt —— 统一管理编译规则(推荐 CMake)
- 避免把 .h 和 .cpp 混在同一个扁平目录下,也不建议每个类建独立子目录(过度设计)
基本上就这些。不复杂但容易忽略——坚持“头文件只声明、源文件只定义”,再配上合理的目录和包含习惯,多文件 C++ 项目就能稳定、可读、易协作。









