ошибка LNK2005: уже определена – C ++

Задний план

У меня есть проект под названием PersonLibrary, который имеет два файла.

  1. Person.h
  2. Person.cpp

Эта библиотека создает файл статической библиотеки. Другим проектом является 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 и определил весь class в Person.h . Ошибка исчезла, и все сработало.

2 – Изменен модификатор SetPersonName на статический . Как ниже

 static void SetPersonName(Person& person,const std::string name) { person.SetName(name); } 

Вопросов

  1. Почему первый код не работает, как я ожидал?
  2. Какая разница статична здесь?
  3. Каково приемлемое решение этой проблемы?

благодаря

Вы либо должны

  • переместить определение SetPersonName в файл .cpp, скомпилировать и связать с результирующей целью
  • сделать SetPersonName встроенным

Это хорошо известный случай нарушения правила одного определения.

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

Когда вы компилируете библиотеку, ее файл lib содержит определение для SetPersonName. Когда вы компилируете свою программу, которая использует библиотеку, так как она включает заголовок, и вы написали встроенный код в заголовок, он также компилируется в определении для SetPersonName. Два определения для одной и той же функции не разрешены (обычно). Статическое ключевое слово сообщает компилятору, что функция не должна отображаться вне текущей единицы перевода (дискретный fragment кода, который вы компилируете), поэтому определение в библиотеке не отображается в компоновщике.

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

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

Объявляя статическую функцию, вы просматриваете ее до текущей единицы перевода, так что вы добавили новую функцию 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); } 
  1. Функция SetPersonName будет скомпилирована в каждый объектный файл, который включает файл Person.h, что делает компоновщик видя несколько функций и выдавая ошибку.

  2. При написании static вы указываете, что функция будет видна только в одном объектном файле. Вы все равно получите несколько функций в вашем двоичном коде, но теперь вы не получите ошибок.

  3. Попробуйте написать inline перед функцией, подобной

     inline void SetPersonName(Person& person,const std::string name) { person.SetName(name); } 

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

Решением было бы сделать эту функцию статическим методом. Это остановит «уже определенные» ошибки.

У меня была такая же ситуация, как описано выше @ logan-capaldo.

Исходный файл CPP (myfile.cpp) содержит функцию MyFunction. При построении это было скомпилировано в myfile.obj. Но основной файл CPP (main.cpp) также включал myfile.cpp, поэтому функция MyFunction включалась / скомпилировалась / была связана дважды, что привело к ошибке «LNK2005 уже определена».

Это грязно, но у меня не было времени исправить это правильно. Самое быстрое исправление (в VS Express 2012) состояло в том, чтобы щелкнуть правой кнопкой мыши файл myfile.cpp в обозревателе решений, перейдите в «Свойства» и измените «Исключено с сборки на« Да ». Я предполагаю, что это предотвращает создание и / или соединение одного из файлов OBJ и поэтому устраняет ошибку.

  • Шаблон C ++, ссылка на ошибку
  • Передача gcc непосредственно для связывания библиотеки статически
  • ошибка LNK2038: обнаружено несоответствие для '_ITERATOR_DEBUG_LEVEL': значение '0' не соответствует значению '2' в main.obj
  • Что означает «статически связанное» и «динамически связанное»?
  • Могу ли я смешивать статические и общедоступные библиотеки при связывании?
  • Что такое Microsoft Visual Studio, эквивалентная опции GCC ld - whall-archive
  • Используйте как статические, так и динамически связанные библиотеки в gcc
  • ошибка LNK2019: неразрешенный внешний символ _main, указанный в функции ___tmainCRTStartup
  • Давайте будем гением компьютера.