LNK1169 найден один или несколько кратно определенных символов И LNK2005 - PullRequest
0 голосов
/ 15 октября 2018

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

Ошибка 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

вот структура моего кода:

function

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;

header.выглядит так: #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 Ответ

0 голосов
/ 15 октября 2018

Когда вы строите свой проект, каждый файл .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, оставив в заголовке только прототип функции.

Константы.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..

Просто имейте в виду, что assert, объявленный в 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);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...