海湾合作委员会多重定义..仅释放

gcc Multiple definition...release only

本文关键字:定义 释放 委员会      更新时间:2023-10-16

我在头文件中定义了一个函数。在调试中,它可以很好地编译和链接。在发布中,对于包含标头的每个类的每个对象文件,我收到编译错误"'blah::blah(blah&blah)'的多个定义"。

我正在使用 gcc-4.8.1。我无法发布实际代码,此版本已更改名称以保护无辜者:

#ifndef INCLUDE_SMELLS_FUNNY
#define INCLUDE_SMELLS_FUNNY
#include "ParentClass.h"
#include "ChildClassA.h"
#include "ChildClassB.h"
namespace someplace {
bool smellsFunny(const ParentClass& someData) {
  // All ChildClass As smell funny
  if(dynamic_cast<const ChildClassA*>(&someData)) {
    return true;
  }
  // If ChildClass B, need to check if smells funny
  const ChildClassB* childB = dynamic_cast<const ChildClassB*>(&someData)
   if(childB) {
    return childB->MoreThanAWeekOld();
  }
  // Default is smells OK
  return false;
}
}
#endif // INCLUDE_SMELLS_FUNNY

我无法找到哪个 gcc 标志负责。当然,修复只是将实现移动到 cpp 文件中。但为什么这是必要的呢?为什么这只发生在发布中?

这是因为

您在头文件中定义了函数,然后将该头文件包含在多个源文件中。这意味着该函数将在包含标头的每个源文件(技术上是翻译单元)中定义。

对此有几种解决方案:

  1. 将函数标记为 static 。这意味着不会导出翻译单元中的每个定义。
  2. 将函数标记为 inline 。这与第一种选择基本相同。
  3. 将函数的定义放在源文件中,并且仅在头文件中具有其声明

对于像您这样的小函数,则备选方案 2 可能是一个不错的函数。如果你有一个更大的函数,不容易内联,你应该使用备选方案3。

此外,如果使用数字 3,则无需包含头文件,然后降低循环包含的风险。

由于您已将函数定义放在标头中,因此需要将其标记为inline

inline bool smellsFunny(const ParentClass& someData) { ...

这是因为包含标头的每个位置都将具有函数的定义,从而打破了一个定义规则 (ODR)。 inline允许您绕过 ODR。

至于为什么在发布模式下没有问题,这是没有意义的:代码不正确。可能是发布模式正在为您内联声明函数。

我不能确切地说,但也许在调试模式下,该函数被视为内联函数。

如果函数在头文件中,则需要将其声明inline,除非它是在类中定义的。