【C++】头文件的能力与禁忌
在C++中,头文件(.h/.hpp) 的主要作用是声明接口和共享代码,但如果不规范使用,会导致编译或链接错误。以下是详细总结:
一、头文件中可以做的事情
1.1 声明
- 函数声明(无需inline)
// utils.h
void print(); // 声明
- 类或者结构体声明
class MyClass {
public:void foo(); // 成员函数声明
};
- 外部变量声明(用extern)
如果不想用extern,可以使用C++17支持的内联全局变量
extern int globalVar; // 声明,定义在.cpp中
1.2 定义
- 内联函数的定义
inline int add(int a, int b) { return a + b; } // 解决ODR问题
- 类或者结构体成员函数定义
class Vector {
public:float x, y;float length() const { return std::sqrt(x*x + y*y); } // 隐式inline
};
- 模板定义
template<typename T>
T max(T a, T b) { return (a > b) ? a : b; } // 模板必须完整定义在头文件
- 常量表达式(C++11)
constexpr float PI = 3.1415926f; // 内部链接,每个编译单元独立副本
- C++17内联变量
inline int globalConfig = 42; // 允许头文件中定义全局变量
1.3 其他
- 宏定义(谨慎使用)
- 类型别名(using 或者 typedef)
- 命名空间
二、头文件中不可以做的事情
1.1 普通函数定义
原因:违反ODR规则,多个编译单元生成相同符号,链接冲突。
// utils.h
void print() { std::cout << "Hello"; } // ❌ 多个.cpp包含时链接错误
1.2 非内联全局变量定义
int globalVar = 42; // ❌ 多个.cpp包含时链接错误
1.3 静态全局变量
问题:每个包含该头文件的.cpp会生成独立的 localVar,浪费内存。
static int localVar = 0; // ⚠️ 每个编译单元独立副本,可能不符合预期
1.4 复杂代码逻辑
避免在头文件中写长函数或复杂逻辑(如文件操作、动态内存分配)。
原因:增加编译时间,代码膨胀。