LNK1169找到一个或多个乘法定义的符号,并且LNK2005

时间:2018-10-15 14:21:23

标签: c++ class header linker

当我尝试编译代码时遇到了这个问题 我认为这可能是由彼此包括的头文件引起的。但据我所知,我的头文件没有发现任何问题

  

错误LNK1169一个或多个乘法定义的符号   找到作业2 D:\ 05Development \ 04 C_C ++ \ C \ DS Alg   class \ Homework2 \ Debug \ Homework2.exe 1

还有一个错误,告诉我函数Assert()已在其他地方声明。

  

错误LNK2005“ void __cdecl Assert(bool,class   std :: basic_string,class   std :: allocator>)“   (?Assert @@ YAX_NV?$ basic_string @ DU?$ char_traits @ D @ std @@ V?$ allocator @ D @ 2 @@ std @@@ Z)   已在DataBase.obj Homework2 D中定义:D:\ 05Development \ 04   C_C ++ \ C \ DS Alg类\ Homework2 \ Homework2 \ dbTest.obj 1

这是我的代码的结构:

功能

void Assert(bool val, string s)
{
    if (!val)
    {
        cout << "Assertion Failed!!: " << s << endl;
        exit(-1);
    }
}

位于Constants.h

虚拟类列表包含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");

在数据库类中,我创建了一个AList成员

private:
    AList<CData> set;

标题看起来像这样:     #pragma一次     #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 :(得分:3)

在生成项目时,每个.cpp文件都会分别编译为不同的目标文件。 once中的#pragma once仅适用于单个.cpp文件的编译,不适用于整个项目。因此,如果.cpp文件包含标头A和标头B,并且标头B也包含标头A,则将跳过标头A的第二个包含。

但是,如果您还有另一个包含A的.cpp文件,则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发行时被编译出去(以加快执行速度),因此请不要在具有副作用。

#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);