Ошибка LNK2005: уже определена - С++
Фон
У меня есть проект с именем PersonLibrary, который имеет два файла.
Эта библиотека создает файл статической библиотеки. Другим проектом является TestProject, который использует PersonLibrary (добавлен как зависимостей от проекта в VS008). Все работало нормально до тех пор, пока я не добавил функцию Person, не являющуюся членом. Person.h выглядит как
class Person
{
public:
void SetName(const std::string name);
private:
std::string personName_;
};
void SetPersonName(Person& person,const std::string name)
{
person.SetName(name);
}
Person.cpp определяет функцию SetName. Когда я пытаюсь использовать SetPersonName из TestProject, я получаю ошибку LNK2005: уже определен. Вот как я его использовал
#include "../PersonLibrary/Person.h"
int main(int argc, char* argv[])
{
Person person;
SetPersonName(person, "Bill");
return 0;
}
Обходные методы были проверены
1 - Я удалил Person.cpp и определил весь класс в Person.h. Ошибка исчезла, и все сработало.
2 - Изменен модификатор SetPersonName на статический. Как ниже
static void SetPersonName(Person& person,const std::string name)
{
person.SetName(name);
}
Вопросы
- Почему первый код не работает так, как я ожидал?
- Какая разница, сделанная здесь?
- Какое подходящее решение для этой проблемы?
Спасибо
Ответы
Ответ 1
Вы должны либо
- переместить
SetPersonName
в файл .cpp, скомпилировать и связать с результирующей целью
- make
SetPersonName
inline
Это хорошо известный случай нарушения правила определения.
Статическое ключевое слово делает внутреннюю привязку функции доступной только для единицы перевода, в которую она включена. Это, однако, скрывает реальную проблему. Я бы предложил переместить определение функции в свой собственный файл реализации, но сохранить объявление в заголовке.
Ответ 2
Когда вы компилируете свою библиотеку, ее файл lib содержит определение для SetPersonName. Когда вы компилируете свою программу, которая использует библиотеку, так как она включает заголовок, и вы написали встроенный код в заголовок, он также компилируется в определении для SetPersonName. Два определения для одной и той же функции не разрешены (обычно). Статическое ключевое слово сообщает компилятору, что функция не должна быть открыта за пределами текущей единицы перевода (дискретный фрагмент кода, который вы компилируете), поэтому определение в библиотеке не отображается в компоновщике.
Соответствующее решение этой проблемы зависит от ваших целей. Заголовочные файлы со статическими объявлениями функций почти никогда не нужны. С точки зрения дизайна я бы рекомендовал полностью избавиться от SetPersonName и просто использовать Person:: SetName.
Однако, если это не так, я бы реализовал его так же, как и для остальных ваших функций, деклараций в заголовке и реализации в .cpp. Встроенные функции, связанные с библиотекой, будут иметь тенденцию к уменьшению многих преимуществ использования библиотеки в первую очередь.
Ответ 3
-
Функция SetPersonName будет скомпилирована в каждый объектный файл, включающий файл Person.h, что сделает компоновщик увиденным несколько функций и даст ошибку.
-
Записывая static, вы указываете, что функция будет видна только в одном объектном файле. Вы все равно получите несколько функций в вашем двоичном коде, но теперь вы не получите ошибок.
-
Попробуйте написать inline
перед функцией вроде
inline void SetPersonName(Person& person,const std::string name)
{
person.SetName(name);
}
... потому что функция довольно проста, это нормально. Я думаю, что это как встроенный. В строке поместится необходимый код, в котором используется функция, без фактического создания функции, которая будет вызываться.
Ответ 4
Объявляя статическую функцию, вы просматриваете ее до текущей единицы перевода, так что вы добавили новую функцию SetPersonName в свой основной файл и вызывали бы это не то, что определено в библиотеке.
Правильное решение - объявить SetPersonName как extern in person.h и реализовать его в person.cpp
Person.h
extern void SetPersonName(Person& person,const std::string name);
Person.cpp
void SetPersonName(Person& person,const std::string name)
{
person.SetName(name);
}
Ответ 5
Решение было бы сделать эту функцию статическим методом. Это остановит "уже определенные" ошибки.
Ответ 6
У меня была аналогичная ситуация, как описано выше @logan-capaldo.
В исходном файле CPP (myfile.cpp) содержится функция MyFunction. При построении это было скомпилировано в myfile.obj. Но основной файл CPP (main.cpp) также включал myfile.cpp, поэтому функция MyFunction включалась/скомпилировалась/была связана дважды, что привело к ошибке "LNK2005 уже определена".
Это грязно, но у меня не было времени исправить его правильно. Самое быстрое исправление (в VS Express 2012) состояло в том, чтобы щелкнуть правой кнопкой мыши файл myfile.cpp в обозревателе решений, перейдите в "Свойства" и измените "Исключено с сборки на" Да ". Я предполагаю, что это предотвращает создание и/или привязку одного из файлов OBJ и устраняет эту ошибку.