Как найти несколько определений функции - PullRequest
4 голосов
/ 21 мая 2011

Я написал findDialog, который находит искомый текст. Когда я даю команду make, она возвращает

g++ -Wl,-O1 -o findDialog FindDialog.o main.o moc_FindDialog.o    -L/usr/lib -lQtGui -lQtCore -lpthread 
moc_FindDialog.o: In function `FindDialog::findClicked()':
moc_FindDialog.cpp:(.text+0x20): multiple definition of `FindDialog::findClicked()'
FindDialog.o:FindDialog.cpp:(.text+0x30): first defined here
moc_FindDialog.o: In function `FindDialog::enableFindButton(QString const&)':
moc_FindDialog.cpp:(.text+0x50): multiple definition of `FindDialog::enableFindButton(QString const&)'
FindDialog.o:FindDialog.cpp:(.text+0x0): first defined here
collect2: ld returned 1 exit status
make: *** [findDialog] Error 1

Я искал проблему часами, но не могу понять, из-за чего проблема. Что может вызвать multiple definition of ошибку?

Ответы [ 4 ]

18 голосов
/ 21 мая 2011

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

Имеет заголовочный файл 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 ++, не понимая, как это влияет на программу. Я бы порекомендовал использовать определение в исходном файле и сделать его встроенным, только если вызов этой функции становится узким местом производительности, а в противном случае его встроенное исправит.

Надеюсь, это поможет. Удачного кодирования!

5 голосов
/ 21 мая 2011

Запись определений функций в файлах заголовков, а затем #include в этих файлах заголовков за несколько .cpp с вашего проекта. Вопреки распространенному заблуждению, охранники заголовков не защищают вас от этого.

В заголовках пишите только следующее:

  • Определения классов
    • Может включать встроенные определения для функций-членов
  • Объявления переменных, не являющихся членами
  • Объявления функций, не являющихся членами
  • Определения шаблонов / встроенных функций

Поместите все остальное в "исходные файлы".

1 голос
/ 12 июля 2012

Влад Владзенко ответил хорошо.

Я просто добавил еще одну возможность, с которой я столкнулся при использовании QT / C ++:

Когда вы объявляете слот, вам не нужно писать определение (реализацию), в противном случае вы получите ошибку: множественное определение

0 голосов
/ 21 мая 2011

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

moc_FindDialog.cpp: multiple definition of `FindDialog::findClicked()'
FindDialog.cpp:     first defined here

moc_FindDialog.cpp: multiple definition of `FindDialog::enableFindButton(QString const&)'
FindDialog.cpp:     first defined here

Это ясно говорит о том, что компоновщик впервые столкнулся с каждым из определений функцийв moc_FindDialog.cpp, а затем встретил второе определение в FindDialog.cpp.

Я думаю, что вам нужно внимательно посмотреть на фиктивный тестовый прибор в moc_FindDialog.cpp и определить, почему эти две функции реплицируются.Или, может быть, вы не должны связывать фиктивные функции и реальные функции в одной программе - эти два исходных файла просто не предназначены для объединения в одну программу.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...