
头文件在 C 里“看似只是复制粘贴”实则承担了5 大类刚性任务下面每类给一段最小可跑代码一眼就能看出“如果没有头文件得写多脏”。提供声明——让翻译单元通过编译场景A.cpp 想调用 B.cpp 里定义的函数编译 A 时只拿到声明即可不必把 B 整段粘过来。例子1234567891011//-------------- math_tools.hpp --------------#pragma oncedoubleadd(double,double);// 声明//-------------- math_tools.cpp --------------doubleadd(doublea,doubleb) {returna b; }//-------------- main.cpp --------------------#include math_tools.hpp#include iostreamintmain(){std::cout add(3, 4);// 5}去掉头文件就得把add的完整定义抄进main.cpp失去分离编译的意义。2 暴露类 / 模板——实现接口与实现分离场景库只暴露“怎么用”隐藏“怎么干”。例子1234567891011121314151617181920212223//------------- circle.hpp ------------------#pragma onceclassCircle{// 公开接口public:Circle(doubler);doublearea()const;private:doubleradius_;};//------------- circle.cpp ------------------#include circle.hpp#include numbersCircle::Circle(doubler): radius_(r) {}doubleCircle::area()const{returnstd::numbers::pi * radius_ * radius_;}//------------- main.cpp --------------------#include circle.hpp#include iostreamintmain(){Circle c(1.0);std::cout c.area();// 3.14159...}编译main.cpp只需知道类的大小和调用约定具体算法在circle.cpp里改不动主程序。3 模板 内联代码——“实现也必须可见”场景模板在实例化时需要完整定义内联函数同理。例子12345678910111213//-------------- utils.hpp ------------------#pragma oncetemplateclassTT max(T a, T b){return(a b) ? a : b; }inlineintsqr(intx){returnx * x; }//-------------- main.cpp -------------------#include utils.hpp#include iostreamintmain(){std::cout max(3.5, 2.7) \n;// 3.5std::cout sqr(5) \n;// 25}若把模板定义放到.cpp其他翻译单元实例化maxdouble时会报“未定义”。4 宏、常量、条件编译——跨文件共享“编译期开关”场景同一套源码调试/发布、不同平台用不同宏。例子123456789101112//-------------- config.hpp -----------------#pragma once#define VERSION 202506L#define DEBUG_LOG(x) do{ if constexpr(DEBUG) std::cerr x \n; }while(0)constexprboolDEBUG true;//-------------- main.cpp -------------------#include config.hpp#include iostreamintmain(){DEBUG_LOG(debug mode on);std::cout ver VERSION;}改一行宏全体翻译单元同时生效无需手动改 N 个.cpp。5 前向声明 包含守卫——减少重复解析加速编译场景大型工程里 A 用 B、B 用 C若直接#include b.cpp会无限递归且爆炸。例子123456789101112//-------------- foo_fwd.hpp -------------- // 仅前向声明#pragma onceclassFoo;// 不完整类型voidprocess(constFoo);// 接受引用/指针即可//-------------- foo.hpp ------------------- // 完整定义#pragma once#include foo_fwd.hppclassFoo{intvalue{}; };voidprocess(constFoo f){/*...*/}//-------------- main.cpp -------------------#include foo.hppintmain(){ Foo f; process(f); }通过“守卫宏”#pragma once或传统#ifndef保证同一头文件在一个翻译单元里只展开一次前向声明让“仅需指针/引用”的地方不必拉入完整定义显著降低编译量。一句话总结头文件 跨翻译单元的“公共契约”声明函数/类/模板→让编译通过暴露接口→隐藏实现共享宏与常量→统一行为前向声明守卫→加速构建。没有它C 的“分离编译”模型就彻底崩塌。