函数已经在C ++中定义了错误

时间:2011-08-06 04:41:24

标签: c++ include linker-errors

我有一个名为“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”中定义。

但是,由于我使用的是包含警卫,我希望这些函数只定义一次,或者我错过了什么?

3 个答案:

答案 0 :(得分:25)

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

一些可能的解决方案是:

  1. 将函数声明为static,表示内部链接
  2. 内联函数
  3. 将实现移出标题并进入c / c ++文件
  4. 在这里阅读更多内容: What is external linkage and internal linkage?

    顺便说一句,包括警卫保护单个翻译单元多次包含头文件。这是你在这里看到的另一个问题。

答案 1 :(得分:4)

使用'inline'

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); }

编译器不一定要内联代码(虽然可以使用这个简短的函数),但链接器不再将其作为单独的函数处理。

注意 - 包含警卫会停止在同一源文件中多次包含相同的包含文件(严格来说,“编译单元”)它不会阻止它包含在链接在一起的单独源文件中。这就是为什么你通常在标题中声明它但在c文件中定义函数

答案 2 :(得分:1)

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

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