【问题标题】:Function already defined error in C++C ++中的函数已定义错误
【发布时间】:2011-08-06 04:41:24
【问题描述】:

我有一个名为“SimpleFunctions.h”的文件,定义如下:

#ifndef SIMPLEFUNCTIONS_H
#define SIMPLEFUNCTIONS_H

namespace my_namespace {

double round(double r) { return (r > 0.0) ? floor(r + 0.5) : ceil(r - 0.5); }
float round(float r) { return round((double)r); }

}

#endif // SIMPLEFUNCTIONS_H

此文件以前只包含在一个文件中,并且工作正常。

现在我已将它包含在第二个文件中,但它不再有效。在链接时,它告诉我该函数已在“firstfile.obj”中定义。

但是,由于我使用的是包含守卫,我希望这些函数只定义一次,还是我遗漏了什么?

【问题讨论】:

标签: c++ include linker-errors


【解决方案1】:

默认情况下,这些函数具有外部链接。这意味着每个翻译单元都有名为 double round(double r) 和 float round(float r) 的函数,这会在链接时导致名称冲突。

一些可能的解决方案是:

  1. 将函数声明为静态,这意味着内部链接
  2. 内联函数
  3. 将实现移出标头并放入 c/c++ 文件中

在这里阅读更多: What is external linkage and internal linkage?

顺便说一句,包含保护可以防止单个翻译单元多次包含头文件。这与您在此处看到的问题不同。

【讨论】:

【解决方案2】:

使用“内联”

inline double round(double r) { return (r > 0.0) ? floor(r + 0.5) : ceil(r - 0.5); }
inline float round(float r) { return round((double)r); }

编译器不一定会内联代码(尽管对于这个简短的 func 可能),但链接器不再将 is 视为单独的函数。

注意 - 包含保护阻止同一个包含文件在同一个源文件中多次包含(严格来说是“编译单元”),它不会阻止它被包含在链接在一起的单独源文件中。这就是为什么您通常在头文件中声明它但在 c 文件中定义函数的原因

【讨论】:

  • 成功了,谢谢。不过我很好奇 - 为什么编译器包含两次文件,即使有一个包含保护?
  • 它是一个单独的翻译单元——宏定义不跨越翻译单元(编译器调用)。链接器现在有 2 个循环定义和错误输出。 static 也适用于解决问题。
【解决方案3】:

解决问题的更好方法是通过模板。如果您按照以下方式执行某些操作,您的代码将编译得很好:

template <class T>
T round (T r) {
    return (r > 0.0) ? floor(r + 0.5) : ceil(r - 0.5);
}

您的链接器将停止抱怨,您将拥有满足所有需求的单一功能。

这个解决方案可以通过类型特征来改进。见boost::is_floating_pointboost::enable_if

【讨论】:

  • 你作弊,但以一种好的方式。有用。它甚至是某些场景的最佳解决方案!谢谢。
猜你喜欢
  • 1970-01-01
  • 2022-05-03
  • 2021-06-08
  • 1970-01-01
  • 1970-01-01
  • 2010-10-11
  • 2016-11-21
相关资源
最近更新 更多