Подтвердить что ты не робот

Ошибка LNK2005: уже определена - С++

Фон

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

  • Person.h
  • 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 и определил весь класс в Person.h. Ошибка исчезла, и все сработало.

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

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

Вопросы

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

Спасибо

4b9b3361

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