class 主体外定义的 C++ 成员函数的编译

Compilation of C++ member functions defined outside the class body

我有这样一个 hpp 文件:

#ifndef __MYLIB_H
#define __MYLIB_H

class A {
public:
  void func1();
  void func2();  
};

void A::func1() {
  // maybe do something
}

#endif

对应的cpp文件中有func2的实现。头文件包含在项目中的其他文件中(这些文件包含在更多文件中)。当我尝试构建它时,我收到 func1 的 "multiple definition" 链接器错误。为什么会这样?因为我用#ifndef保护了头文件,没想到会报错

如果我在 func1 的定义中添加关键字 inline,那么一切都很好。所以如果我不关心被内联的函数并且我不想在 class 主体中有定义,我不能在 hpp 文件中包含它的定义?如果有人可以解释这里发生了什么,那将非常有帮助。我正在使用 GCC 6。

实现通常放在相关的 .cpp 文件中。将它们放在 header 中是有问题的。 inline 是一种解决此问题的 hack,您可能不想使用它,因为它会在该代码出现的任何地方都将其删除,从而导致大量重复。

请记住,#include 非常类似于将该文件粘贴到该指令出现的代码中。一个函数有多个实现是不正确的,这就是为什么它们在 header 之间分开用于签名目的,因此理解如何正确使用这些函数,以及实际代码的实现。

问题是您在每个文件中重新定义 func1

#include 指令是一个非常简单的命令,它只是将 header 文件的内容粘贴到指定的位置。

这样做的结果是,每次您 #include 您的 header 您在该文件中 "redefining" func1

回想一下,整个 header 的内容以及它可能包含的任何文件实际上都 "copy-pasted" 到每个 翻译单元* 在包含点包含 header。

这就是为什么在多个 CPP 文件中包含 header 的效果与将 copy-pasted 函数定义字面意思写入每个 CPP 的效果相同,即它与编写多个相同相同 member-function.

的相同定义

通过声明函数inline解决了问题,因为C++允许定义多个内联函数,只要它们彼此相同即可。将函数的 body 移动到 class 的声明中也可以,因为这样的函数会被自动视为 inline.

* 在这种情况下,"translation unit" 是您的 CPP 文件的奇特名称。