Несколько определений одной и той же функции в C ++ - PullRequest
0 голосов
/ 02 марта 2019

Я пишу библиотеку для нейронных сетей.Есть некоторые необходимые функции, которые мне нужны, поэтому я выделил их в отдельный заголовочный файл.Я также предоставил определение охранникам.Я также включил заголовочный файл только в один файл, но затем компоновщик утверждает, что в программе есть несколько определений всех функций.Структура библиотеки выглядит следующим образом:

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

этот файл functions.hpp включен только один в neuron.hpp, и поскольку ffnet зависит от нейрона, я включил neuron.hpp в ffnet только один раз.Этот 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 голосов
/ 02 марта 2019

Вы должны написать код random_double() в файле .cpp, отличном от файла .hpp или .h.Или добавьте inline перед double random_double() { //some code }, если вы храните свой код в файле .hpp.

0 голосов
/ 02 марта 2019

Проблема

У вас есть определение функции с полным кодом в заголовке, который вы включаете в несколько модулей компиляции.Это приводит к определению функции в каждой единице компиляции (cpp) и нарушает Правило единого определения (ODR) .

Включающие охранники следят за тем, чтобы одно и то же определение не встречалось несколько раз в одном и том же модуле компиляции (например, если вы включили function.hpp в neuron.hpp, а также включили его напрямую).Но здесь этот заголовок прямо или косвенно включен в main.cpp, ffnet.cpp и neuron.cpp, что дает первое определение и 2 недопустимых переопределения.

Решение

Вы должны изменить function.hpp, чтобы сохранить только объявление функции:

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

и переместить тела функций в отдельный function.cpp, который долженбыть добавлен к вашей команде компилятора.

Преимущество этого подхода:

  • Затем вы можете скомпилировать служебные функции отдельно.Каждый раз, когда вы меняете тело функции, вам больше не нужно перекомпилировать весь cpp.
  • Инкапсуляция улучшена за счет совместного использования в hpp только того, что нужно знать другим модулям, и сокрытия деталей реализации.
  • Повторное использование может быть облегчено во всех проектах путем создания библиотеки функций.
  • Включения будут короче (в случае, если в некотором отдаленном будущем ваш код превратится в большой проект с тысячами hpp, это может заставить вас выиграть некоторое время)

Дополнительные замечания

Не уверен, что это применимо, но имейте в виду, что не стоит включать заголовок в пространство имен.

Я также рекомендую прочитать эту статью о заголовках .Это старый, но совет все еще очень актуален: -)

Обратите внимание, что существуют исключения из ODR для классов и встроенных функций, и в этом случае множественные определения должны быть точно такой же последовательностью токенов.

...