ошибка LNK2005: уже определена – C ++
Задний план
У меня есть проект под названием PersonLibrary, который имеет два файла.
- Person.h
- Person.cpp
Эта библиотека создает файл статической библиотеки. Другим проектом является TestProject, который использует PersonLibrary (добавлен как зависимостей от проекта в VS008). Все работало нормально до тех пор, пока я не добавил функцию Person, не являющуюся членом . Person.h выглядит
- Могу ли я смешивать статические и общедоступные библиотеки при связывании?
- Порядок инициализации статических переменных
- ошибка LNK2019: неразрешенный внешний символ _main, указанный в функции ___tmainCRTStartup
- Как C ++-связь работает на практике?
- ошибка LNK2038: обнаружено несоответствие для '_ITERATOR_DEBUG_LEVEL': значение '0' не соответствует значению '2' в main.obj
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); }
Вопросов
- Почему первый код не работает, как я ожидал?
- Какая разница статична здесь?
- Каково приемлемое решение этой проблемы?
благодаря
- Почему при использовании шаблонов я получаю ошибки «неразрешенных внешних символов»?
- Как удалить пакет из Laravel с помощью композитора?
- Что такое опция -fPIE для независимых по позиции исполняемых файлов в gcc и ld?
- Что означает «статически связанное» и «динамически связанное»?
- VA (виртуальный адрес) и RVA (относительный виртуальный адрес)
- Почему порядок, в котором связаны библиотеки, иногда вызывает ошибки в GCC?
- Почему компиляторы настолько глупы?
- Как принудительно включить определение «неиспользуемых» объектов в библиотеке
Вы либо должны
- переместить определение
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); }
-
Функция SetPersonName будет скомпилирована в каждый объектный файл, который включает файл Person.h, что делает компоновщик видя несколько функций и выдавая ошибку.
-
При написании static вы указываете, что функция будет видна только в одном объектном файле. Вы все равно получите несколько функций в вашем двоичном коде, но теперь вы не получите ошибок.
-
Попробуйте написать
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 и поэтому устраняет ошибку.