ошибка 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 и поэтому устраняет ошибку.

  • Почему фатальная ошибка «LNK1104: невозможно открыть файл« C: \ Program.obj »возникает при компиляции проекта C ++ в Visual Studio?
  • Ошибки компоновщика при компиляции против glib ...?
  • Что означает «статически связанное» и «динамически связанное»?
  • Определение переменной в файлах заголовков
  • Почему порядок, в котором связаны библиотеки, иногда вызывает ошибки в GCC?
  • Как C ++-связь работает на практике?
  • Почему при использовании шаблонов я получаю ошибки «неразрешенных внешних символов»?
  • ошибка LNK2038: обнаружено несоответствие для '_ITERATOR_DEBUG_LEVEL': значение '0' не соответствует значению '2' в main.obj
  • Interesting Posts

    Почему 32-битные ОС не могут адресовать более 3,2 ГБ памяти?

    Каков лимит вызовов API в Facebook?

    Есть ли вероятность того, что IP-пакет с одним и тем же IP-адресом источника и получателем может попасть в сеть?

    Как параметризовать @Scheduled (fixedDelay) с языком выражения Spring 3.0?

    Как установить layout_gravity программно?

    Как отправить электронную почту в фоновом режиме на Android?

    Windows 7 – просмотр других типов файлов в виде текста в области предварительного просмотра

    Как сохранить профили запуска Eclipse в рабочих пространствах?

    Размер изображения для всех экранных устройств

    ASP.NET как визуализировать элемент управления HTML?

    Почему я не могу подключиться к беспроводной сети на ubuntu, но Mac в порядке?

    Неверный внешний ключ плохой практики?

    В чем разница между квадратными скобками и круглыми скобками в регулярном выражении?

    Как получить день месяца?

    Текстовое поле / richtextbox с подсветкой синтаксиса?

    Давайте будем гением компьютера.