【学习笔记】头文件中定义函数出现重复定义报错
错误复现
现在有一个头文件 duplicate_define.h 和两个源文件 duplicate_define_1.cpp 和 duplicate_define_2.cpp。
两个源文件都引入了头文件 duplicate_define.h,且在各自的函数中调用了定义在头文件中的全局函数 duplicateFunction()。
头文件中添加了 #pragma once 来方式头文件重复包含。
现在如果进行编译链接操作,会出现报错,我们以 vs 为例看一下具体的报错内容
原因
工程在编译时,每个编译单元(简单来说就是源文件以及引入的头文件构成了编译单元)都会引入头文件,也就是说 duplicate_define_1.cpp 和 duplicate_define_2.cpp 都在各自组成的编译单元中,引入(复制一份)了头文件 duplicate_define.h。
这导致每个编译单元都定义了相同的函数,也就是位于头文件中的 duplicateFunction(),而在链接时就会发现重复的函数。
解决方案
inline
inline 关键字赋予了函数“允许重复定义”的特性。在链接阶段,链接器从重复的 inline 函数中选择一个,而忽略其他副本。
当头文件中的函数定义为 inline 后,可通过编译。
static
static 关键字会改变函数和变量的链接属性,默认情况下全局变量和函数是外部链接,也就是它们可以被其他编译单元使用。
但一个添加了 static 的函数或变量只在它定义的编译单元中可见,这样,每个包含类似上面头文件的源文件都独立拥有 duplicateFunction(),在链接时互不冲突。
但正是因为独立拥有,所以浪费了空间。
扩展
扩展一
如果在公共头文件中定义类成员函数,为什么这个类成员函数在其他多个 cpp 中被调用时不会出现上述重复定义的问题呢?
答案很简单,因为类成员函数隐含就是内联的。
扩展二 - 头文件定义变量出现重复定义报错
原因也和头文件定义函数出现重复定义报错一样。除了使用 static 或 inline 的方法外,还可以使用 extern 的方式解决。
- 使用 extern 方式
在头文件中声明但不定义
// myheader.h
extern int sharedVariable; // 声明,不定义
在其中一个 cpp 文件中定义
// myvariable.cpp
#include "myheader.h"
int sharedVariable = 10; // 定义并初始化
在另一个 cpp 文件中包含头文件并使用
// another.cpp
#include "myheader.h"
void useVariable() {
sharedVariable = 20; // 使用变量
}
- 使用 inline 方式
如果使用 C17 或更高版本,可以在头文件中使用 inline 来定义变量
// myheader.h
inline int sharedVariable = 10; // C17 特性,避免多重定义
- 使用 static 方式
如果变量只需要在当前编译单元(.cpp)中使用,可以在头文件中使用 static
// myheader.h
static int sharedVariable = 10; // 仅限当前文件,不会导致多重定义
参考
更多推荐



所有评论(0)