包含外部库时出现 C++ 多重定义错误

C++ multiple definition error when including external library

我正在尝试编写一个简单的应用程序,允许用户对一组线性方程式执行一系列符号操作,为此我正在使用 "Symbolicc++" library(更具体地说,最新版本 3.35)目的。

因为我没有太多的 C++ 经验并且以前从未真正使用过 third-party 库,所以我很可能只是不知道如何正确使用库并且正在做一些愚蠢的事情错误。

问题是,当我尝试编译(和 link)任何由多个文件组成的程序时,我得到了 很多 多个定义错误,其中包括图书馆的主要header;错误指的是库文件(不是我的)中定义的函数和 类。

一个非常简单的例子:假设我们有文件 main.cpphead.hhead.cpp。内容如下:

main.cpp
------------------
#include <iostream>
#include "head.h"

int main()
{
    return 0;
}

head.h
------------------
#ifndef SOMETHING
#define SOMETHING

#include "symbolicc++.h"

#endif

head.cpp
------------------
#include "head.h"
//nothing

当然,真实程序中的文件包含更多,但即便如此,尝试构建程序,例如:

g++ -I /path to library's header files/ main.cpp head.cpp

产生数百条错误消息,例如:

/tmp/ccYNzlEF.o: In function `Cloning::Cloning()':
head.cpp:(.text+0x0): multiple definition of `Cloning::Cloning()'
/tmp/ccNWUnnC.o:main.cpp:(.text+0x0): first defined here

其中,例如,Cloning::Cloning()cloning.h 中声明,这是库的其中一个header 个文件。

仅包含 单个 文件(包括 symbolicc++.h 的程序工作正常。

我也在 Visual Studio 2012 年尝试构建这个项目并得到了类似的结果。

不幸的是,我找不到关于这个问题的任何信息,因为我发现的几乎所有资料都与用户创建的 header 文件(与其他人创建的库相对)中的错误有关,因此我们将不胜感激。

这个库似乎严重损坏。按照它的设计方式,您不能在不违反单一定义规则的情况下多次包含 "symbolicc++.h"

例如,让我们看一下cloning.h。它定义了一个带有默认构造函数声明的 Cloning class:

class Cloning
{
 private: int refcount;
          void (*free_p)(Cloning*);
// ...    
 public:  Cloning();
// ...
};

稍后,在头文件中,它还定义构造函数:

Cloning::Cloning() : refcount(0), free_p(0) {}

就是这样。每个直接或间接包含 cloning.h 的 *.cpp 文件都将暴露给同一函数的定义。链接器注意到多个定义并放弃。

尝试修改cloning.h。删除上面的构造函数定义行并将构造函数定义放入 class 定义中,使其成为内联函数:

// just to see what's going on...
class Cloning
{
 private: int refcount;
          void (*free_p)(Cloning*);
// ...

 public:  Cloning() : refcount(0), free_p(0) {};
// ...
};

这将修复 Cloning::Cloning 的错误。但这只是为了更清楚地说明这个问题;我不建议你这样做。 库作者的工作是修复他们的代码。

进一步推荐阅读:Why include guards do not prevent multiple function definitions?


您可以通过以下方式用自己的几行代码重现同样的问题:

head.h:

#ifndef SOMETHING
#define SOMETHING

struct Example
{
    Example(); // constructor declaration
};

Example::Example() // constructor definition
{
}

#endif

head.cpp:

#include "head.h"
//nothing

main.cpp:

#include "head.h"

int main()
{
}

链接器错误示例(取自 Visual C++ 2013):

1>main.obj : error LNK2005: "public: __thiscall Example::Example(void)" (??0Example@@QAE@XZ) already defined in head.obj
1>[...] fatal error LNK1169: one or more multiply defined symbols found

如果您绝对必须使用此库,则必须围绕它构建自己的安全包装器。但坦率地说,只是不要。我敢肯定还有许多其他库可以解决相同的问题,并且实际上可以根据 C++ 语言规则和约定使用它们。