C ++中相同功能的多个定义

时间:2019-03-02 07:00:52

标签: c++ linux ld one-definition-rule multiple-definition-error

我正在编写神经网络库。我需要一些必要的功能,因此我将它们分隔在单独的头文件中。我还提供了定义防护。我还只将头文件包含在一个文件中,但是链接器还声称该程序中所有功能都有多个定义。 库结构如下:

namespace maya:
     class neuron [neuron.hpp, neuron.cpp]
     class ffnet [ffnet.hpp, ffnet.cpp]
     struct connection [connection.hpp]
     functions [functions.hpp]

函数头文件是这样写的:

#ifndef FUNCTIONS_HPP
#define FUNCTIONS_HPP
// some functions here
double random_double(){//some code}
#endif

此function.hpp文件仅在Neuron.hpp中包含一个,并且由于ffnet依赖于神经元,因此我仅在ffnet中包含Neuron.hpp一次。 ffnet.hpp仅在main.cpp中包含一次。 main.cpp是我用于测试库的文件。

此链接器抛出类似以下的错误:
/usr/bin/ld: /tmp/ccN7ywby.o: in function `maya::random_double()': neuron.cpp:(.text+0x0): multiple definition of maya::random_double()'; /tmp/ccvDr1aG.o:main.cpp:(.text+0x0): first defined here

/usr/bin/ld: /tmp/cc66mBIr.o: in function `maya::random_double()':`` ffnet.cpp:(.text+0x0): multiple definition of `maya::random_double()'; /tmp/ccvDr1aG.o:main.cpp:(.text+0x0): first defined here

我也使用:
编译了程序 g++ main.cpp neuron.cpp ffnet.cpp -o net

我认为这不是必需的,但以防万一:
$ uname -a
Linux brightprogrammer 4.19.0-kali3-amd64 #1 SMP Debian 4.19.20-1kali1 (2019-02-14) x86_64 GNU/Linux

2 个答案:

答案 0 :(得分:0)

问题

您可以在包含在多个编译单元中的标头中获得函数定义及其完整代码。这将导致在每个编译单元(cpp)中定义函数,这会破坏One Definition Rule (ODR)

include保护措施可确保同一定义单元中不会多次出现相同的定义(例如,如果您将function.hpp包含在neuron.hpp中,并且也直接包含它)。但是在这里,此标头直接或间接包含在main.cppffnet.cppneuron.cpp中,这形成了第一个定义和2个无效的重新定义。

解决方案

您必须更改function.hpp以仅保留函数声明:

#ifndef FUNCTIONS_HPP
#define FUNCTIONS_HPP
double random_double();  // no body !!
#endif

并将功能主体移至单独的function.cpp,必须将其添加到编译器命令中。

这种方法的优点是:

  • 然后可以分别编译实用程序功能。每次更改函数主体时,您都不再需要重新编译所有cpp。
  • 通过在hpp中仅共享其他模块需要知道的内容并隐藏实现细节来改进封装。
  • 通过构建功能库,可以促进跨项目的重用。
  • 包含的内容会更短(以防将来您的代码演变为具有数千个hpp的大型项目,这可以使您获得一些时间)

其他备注

不确定是否适用,但也请注意将标头包含在名称空间中并不是一个好主意。

我还建议使用reading this article about headers。虽然很旧,但建议仍然非常有用:-)

请注意,类和内联函数的ODR例外,在这种情况下,多个定义必须完全相同的标记序列。

答案 1 :(得分:0)

您必须在.hpp或.h文件以外的.cpp文件中编写random_double()的代码。或者,如果您将代码保存在.hpp文件中,请在inline之前添加double random_double() { //some code }