Обычно это происходит, когда определение метода включено в несколько единиц перевода, также называемых объектными файлами. Позже, когда компоновщик объединяет эти объектные файлы, он обнаруживает, что существует несколько определений одного и того же метода, и жалуется, потому что он не знает, какой из них использовать. Вот простой пример того, как ввести эту ошибку:
Имеет заголовочный файл header.hpp
с объявлением метода и его определением:
class foo {
public:
void bar ();
};
void foo::bar ()
{
}
И иметь два исходных файла source1.cpp и source2.cpp, включая этот файл:
source1.cpp
:
#include "header1.hpp"
int example1()
{
foo f;
f.bar ();
}
... и source2.cpp
:
#include "header1.hpp"
int main ()
{
foo f;
f.bar ();
f.bar ();
}
Затем скомпилируйте два файла отдельно и свяжите их вместе. Например:
g++ -c source1.cpp source1.o
g++ -c source2.cpp source2.o
g++ -o a.out source1.o source2.o
Это даст вам ошибку компоновщика, которую вы описали в своем вопросе, потому что метод foo::bar
появляется дважды, как в объектах source1, так и в source2. Линкер не знает, какой использовать.
Существует два распространенных решения этой проблемы:
Решение № 1 - встроить этот метод.
Объявив этот метод с ключевым словом inline
, компилятор либо встроит весь метод целиком, либо, если он решит не делать этого, сгенерирует анонимный метод (тот же метод, но с некоторым уникальным именем для данного объектного файла), поэтому не будет никаких конфликтов в объектных файлах. Например:
class foo {
public:
void bar ();
};
inline void foo::bar ()
{
}
Решение №2. Определить (реализовать) этот метод в другом исходном файле, чтобы он появлялся во всей программе только один раз. Например:
header1.hpp
class foo {
public:
void bar ();
};
header1.cpp
#include "header1.hpp"
void foo::bar ()
{
}
Чтобы решить, встроить или нет, вы должны знать (или, по крайней мере, сделать предположение), является ли вызов этой функции более дорогим, чем дублирование / вставка этого кода во всей программе. Встроенный код обычно увеличивает размер вашей программы и увеличивает время компиляции. Но это не обязательно делает это быстрее. Кроме того, определение в исходном файле не приведет к повторной компиляции всех исходных файлов с использованием этой функции, а только к повторной компиляции исходного файла с определением, а затем к повторной компоновке. Многие программисты сходят с ума по встраиванию C ++, не понимая, как это влияет на программу. Я бы порекомендовал использовать определение в исходном файле и сделать его встроенным, только если вызов этой функции становится узким местом производительности, а в противном случае его встроенное исправит.
Надеюсь, это поможет. Удачного кодирования!