我有一个像这样的hpp文件:
#ifndef __MYLIB_H
#define __MYLIB_H
class A {
public:
void func1();
void func2();
};
void A::func1() {
// maybe do something
}
#endif
有一个相应的cpp文件,它具有func2的实现。头文件包含在项目中的其他文件中(更多文件包含这些文件)。当我尝试构建这个时,我会得到多个定义" func1
的链接器错误。为什么会这样?由于我使用#ifndef
保护了头文件,因此我没想到错误。
如果我将关键字inline
添加到func1
的定义中,那么一切都很好。因此,如果我不关心内联函数并且我不想在类体中定义,我不能在hpp文件中包含它的定义吗?如果有人能够解释这里发生的事情,那将会非常有帮助。我正在使用GCC 6。
答案 0 :(得分:2)
问题是您要在每个文件中重新定义func1
。
#include
指令是一个非常简单的命令,它只是将头文件的内容粘贴到指定的位置。
结果是,每次#include
标题时,您都会在该文件中“重新定义”func1
。
答案 1 :(得分:2)
回想一下,整个标题的内容及其可能包含的任何文件,实际上是“复制粘贴”到每个翻译单元 * 中,其中包括在包含点的标题。
这就是为什么在多个CPP文件中包含标题的效果与将字符串复制粘贴到每个CPP中的效果相同,即它与您编写同一成员函数的多个相同定义的效果相同
通过声明函数inline
来解决问题,因为C ++允许内联函数的多个定义,只要它们彼此相同即可。将函数体移动到类的声明中也有效,因为这些函数会自动被视为inline
。
* 在此上下文中,“翻译单元”是您的CPP文件的精美名称。
答案 2 :(得分:0)
实现通常包含在关联的.cpp
文件中。将它们放在标题中是有问题的。 inline
是一个可以解决这个问题的黑客,你可能不想使用它,因为它会在它出现的任何地方标记出代码,导致严重的重复。
请记住,#include
非常类似于在该指令出现的代码中粘贴该文件。对于一个函数有多个实现是不正确的,这就是为什么它们在标题之间被分割出来用于签名,所以理解如何正确使用这些函数,以及实际代码的实现。