LNK1169 найден один или несколько кратно определенных символов И LNK2005
Я столкнулся с этой проблемой, когда пытался скомпилировать свой код, я думал, что это может быть вызвано заголовочными файлами, включая друг друга. Но, насколько я могу судить, я не нашел никаких проблем с моими заголовочными файлами
Ошибка LNK1169: найден один или несколько кратно определенных символов Homework2 D:\05Development\04 C_C++\C\DS Alg class\Homework2\Debug\Homework2.exe 1
также есть ошибка, сообщающая, что функция Assert() была объявлена в другом месте.
Ошибка LNK2005 "void __cdecl Assert(bool, класс std::basic_string, класс std::allocator >)" (?Assert@@YAX_NV?$ Basic_string@DU?$ Char_traits@D@std@@V?$ Allocator@D@2@@std@@@Z) уже определено в DataBase.obj Homework2 D:\05Development\04 C_C++\C\DS Alg class\Homework2\Homework2\dbTest.obj 1
вот структура моего кода:
функция
void Assert(bool val, string s)
{
if (!val)
{
cout << "Assertion Failed!!: " << s << endl;
exit(-1);
}
}
находится в Constants.h
Виртуальный класс List включает Constants.h
#pragma once // List.h
#include "Constants.h"
Список массивов включает в себя класс List, в классе AList он вызывает функцию Assert
#pragma once //AList.h
#include "List.h"
...
Assert((pos >= 0) && (pos < listSize), "Position out of range");
В классе DataBase я создал член AList
private:
AList<CData> set;
Заголовок выглядит так: #pragma Once #include "AList.h" #include "CData.h"
и CData.h выглядит так:
#pragma once
class CData
{
private:
std::string m_name;
int m_x;
int m_y;
public:
CData(std::string str = "null", int x = 0, int y = 0) : m_name(str), m_x(x), m_y(y) {}
// Helper functions
const std::string& GetName() const { return this->m_name; }
const int& GetX() const { return this->m_x; }
const int& GetY() const { return this->m_y; }
};
1 ответ
Когда вы строите свой проект, каждый файл.cpp компилируется отдельно в разные объектные файлы. once
в #pragma once
применяется только к компиляции одного файла.cpp, а не для проекта в целом. Таким образом, если файл.cpp содержит заголовок A и заголовок B, а заголовок B также включает заголовок A, то второе включение заголовка A будет пропущено.
Однако, если у вас есть другой файл.cpp, содержащий A, A будет снова включен в этот объектный файл - потому что #pragma once
работает только при компиляции одного файла.cpp.
Инструкция #include буквально берет содержимое включенного файла и "вставляет" его в файл, который его включил. Вы можете попробовать это, посмотрев на вывод инструмента препроцессора C (cpp
в gcc
Набор инструментов). Если вы используете цепочку инструментов gcc, вы можете попробовать что-то вроде этого, чтобы увидеть файл после применения его включений:
cpp file.cpp -o file_with_includes.cpp
Если у вас есть функция в вашем заголовке, как Assert
в вашем примере функция копируется в каждый файл.cpp, в который вы ее включаете.
Если у вас есть A.cpp и B.cpp, которые оба включают ваш файл Constants.h, каждый объектный файл (.o или.obj в зависимости от вашей среды) будет содержать копию вашей функции Assert. Когда компоновщик объединяет объектные файлы для создания двоичного файла, оба объектных файла объявляют, что они предоставляют определение для Assert, и компоновщик будет жаловаться, потому что он не знает, какой из них использовать.
Решение здесь заключается в том, чтобы встроить функцию Assert, например, так:
inline void Assert(bool val, string s)
{
if (!val)
{
cout << "Assertion Failed!!: " << s << endl;
exit(-1);
}
}
или предоставить его тело в своем собственном файле.cpp, оставив в заголовке только прототип функции.
Constants.h:
void Assert(bool val, string s);
Constants.cpp:
void Assert(bool val, string s)
{
if (!val)
{
cout << "Assertion Failed!!: " << s << endl;
exit(-1);
}
}
Имейте в виду, стандартная библиотека также предлагает assert()
, который тоже хорошо работает. (см. https://en.cppreference.com/w/cpp/error/assert).
#include <cassert>
...
assert(is_my_condition_true());
assert(my_variable > 23);
// etc..
Просто имейте в виду, что заявленный в cassert
работает только при компиляции для Debug и компилируется при сборке для Release (для ускорения выполнения), поэтому не помещайте в assert какой-либо код, имеющий побочные эффекты.
#include <cassert>
...
// Don't call functions with side effects.
// Thus function decreases a "count" and returns the new value
// In Release builds, this line will disappear and the decrement
// won't occur.
assert(myclass.decrement_count() > 0);