С++: ошибка множественного определения для глобальных функций в файле заголовка
Эта функция является глобальной и определяется в файле заголовка (временно я хочу сохранить его там).
Заголовочный файл также представляет собой определенный класс, который имеет встроенные функции, и одна из этих функций вызывает эту глобальную функцию.
Исходный файл не содержит вхождения этой глобальной функции.
Любые подсказки о причине ошибки?
Я могу опубликовать код, если кому-то это интересно.
mainwindow.o: In function `tileForCoordinate(double, double, int)':
mainwindow.cpp:(.text+0x310): multiple definition of `tileForCoordinate(double, double, int)'
main.o:main.cpp:(.text+0xd0): first defined here
moc_mainwindow.o: In function `qHash(QPoint const&)':
moc_mainwindow.cpp:(.text+0x0): multiple definition of `qHash(QPoint const&)'
main.o:main.cpp:(.text+0x0): first defined here
moc_mainwindow.o: In function `tileForCoordinate(double, double, int)':
moc_mainwindow.cpp:(.text+0x150): multiple definition of `tileForCoordinate(double, double, int)'
main.o:main.cpp:(.text+0xd0): first defined here
collect2: ld returned 1 exit status
make: *** [SimpleRouting] Error 1
Ответы
Ответ 1
отметьте его как inline
:
inline void globalfunc() {
}
хотя это означает, что он больше не будет строго глобальным - вы получите копию в каждой единицы перевода, которая использует заголовок, но компоновщик не будет возражать против этого.
Ответ 2
Если вы поместите функцию в заголовок, она будет сгенерирована для каждого файла c/cpp, который включает этот заголовок, ведущий к дублированию. Создание встроенного модуля поможет.
Изменить, объяснение
Защитники заголовков, как #ifndef, #define... #endif конструкция часто вызывается только для предотвращения двойного и рекурсивного включения в один файл cpp. Это имеет значение в случае, когда исходный файл включает заголовки A и B и B также включает A. Рекурсивное включение произойдет, если A также включил B.
Ваша проблема возникает из-за того, что у вас есть несколько файлов .cpp. Во время компиляции одного cpp компилятор не знает о существовании других файлов cpp.
Обратите внимание, что #include, #ifdef и друзья - это препроцессорные директивы. Предварительная обработка происходит в исходных файлах перед компиляцией (считается, что это часто рассматривается и выполняется как часть процесса компиляции). Препроцессор в основном представляет собой текстовый процессор. Например, #include по тексту заменяется содержимым файла заголовка. Содержимое #ifdefs, которые оценивают значение false, удаляется из кода. Фактический компилятор получает один большой файл, состоящий из cpp и всех ссылочных файлов include, которые он переводит в объектный файл.
Ответ 3
У вас есть 2 варианта:
Отметьте его как встроенный, как объясняется nbt, или как static.
inline возьмет реализацию глобальной функции от источника и скопирует ее туда, где вызывается функция.
inline void global_func ()
{
...
}
static сообщит компоновщику, чтобы он не копировал код в новый объектный файл, а скорее ссылался только на оригинал.
static void global_func ()
{
...
}
Ответ 4
Для глобальной функции, определенной в заголовочном файле, объявить ее в неименованном пространстве имен должно/также работать. Согласно С++ Как программировать Deitel, в С++ неназванное пространство имен предпочтительнее статического.
Итак, вы можете сделать это:
// \file GlobalFunctions.h
namespace // an un-named namespace
{
void GlobalFunctionOne() {...implementation...}
} // end un named namespace
Ответ 5
#ifndef SOMESTRING
#define SOMESTRING
... header code
#endif
Код заголовка будет включен только в первый раз.