C++ 函数的多个定义,即使是在include保护中定义的

C++ 函数的多个定义,即使是在include保护中定义的,c++,C++,假设我有一个头文件myheader.h,定义如下: #ifndef MY_HEADER #define MY_HEADER int MyFunction(int x) { return x + 1; } #endif 然后,我有两个源文件,它们都#包括这个头文件。这给了我一个编译错误: multiple definitions of 'MyFunction(int)' 为什么我的头文件中的include-guard不能阻止它被定义两次呢?链接器将为包含头文件的每个编译单元传递一个

假设我有一个头文件
myheader.h
,定义如下:

#ifndef MY_HEADER
#define MY_HEADER

int MyFunction(int x)
{
    return x + 1;
}

#endif
然后,我有两个源文件,它们都
#包括
这个头文件。这给了我一个编译错误:

multiple definitions of 'MyFunction(int)'

为什么我的头文件中的include-guard不能阻止它被定义两次呢?

链接器将为包含头文件的每个编译单元传递一个定义

链接器始终只需要1个定义


考虑只在一个源文件中定义函数,或者使用
内联
指令。

您需要标记函数
内联
,如下所示:

#ifndef MY_HEADER
#define MY_HEADER

inline int MyFunction(int x)
{
    return x + 1;
}

#endif
说明

每次在任何.cpp文件中包含.h时,都会得到函数的定义。链接器不喜欢多个定义。然而,若您将函数
标记为inline
,那个么您是在告诉编译器确保链接器会满意

如何使链接器快乐的真正方法取决于编译器和链接器,但实际上,它归结为两种策略:

  • 内联函数-这意味着函数定义实际上从生成的代码中删除。相反,无论函数应该做什么,都会在调用函数的地方进行
  • 将函数标记为本地名-链接器知道本地名是特定于特定文件的,并且将始终保持它们的独立性

    • 声明(.h)不同于定义(.c、.cpp…)

      一个好的做法是在头文件中声明一个函数,在guard内部:

      //file foo.h: can be included in other header or implementation files
      #ifndef MY_HEADER
      #define MY_HEADER 
      int MyFunction(int x);
      #endif
      
      以及在实现文件中定义函数:

      //file foo.c: not included in other files.
      #include "foo.h" // to assert function declaration and definition match
      int MyFunction(int x)
      {
          return x+1;
      }
      

      如果这两个源文件是链接的,那么它们都会将定义编译到其中(因为定义在标题中)。将声明保留在标题中,但将定义移动到单独的源文件中。include guard只能防止在一个翻译单元(一个源文件)中多次包含。这方面没有什么好的做法。有时这是一种合适的方法,有时则不然。