Ошибка множественного определения C++ при включении внешней библиотеки

Я пытаюсь написать простое приложение, позволяющее пользователю выполнять серию символических манипуляций с набором линейных уравнений, и для этой цели я использую библиотеку "SymbolicC++" (точнее, последнюю версию 3.35).

Поскольку у меня нет большого опыта работы с C++ и я никогда раньше не использовал стороннюю библиотеку, вполне возможно, что я просто не знаю, как правильно использовать библиотеку, и делаю какую-то глупую ошибку.

Проблема в том, что я получаю много ошибок определения, когда пытаюсь скомпилировать (и связать) любую программу, состоящую из более чем одного файла, который содержит основной заголовок библиотеки; ошибки относятся к функциям и классам, которые определены в файлах библиотеки (не мои).

Очень упрощенный пример: предположим, у нас есть файлы main.cpp, head.h и head.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, который является одним из заголовочных файлов библиотеки.

Программа, содержащая только один файл, включая symbolicC++. H, работает отлично.

Я также попытался построить этот проект на Visual Studio 2012 и получил аналогичный результат.

К сожалению, я не смог найти никакой информации об этой проблеме, так как практически все найденные материалы касались ошибок в заголовочных файлах, созданных пользователем (в отличие от библиотек, созданных кем-то еще), поэтому любая помощь будет принята с благодарностью.

1 ответ

Решение

Эта библиотека кажется серьезно сломанной. Как это сделано, вы не можете включить "symbolicc++.h" несколько раз без нарушения правила одного определения.

Например, давайте посмотрим на cloning.h, Это определяет Cloning класс с объявлением конструктора по умолчанию:

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

Позже, в файле заголовка, он также определяет этот конструктор:

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

Вот и все. Каждый из ваших *.cpp файлов, который прямо или косвенно включает cloning.h будет подвергаться определению той же функции. Компоновщик замечает несколько определений и сдается.

Попробуйте изменить cloning.h, Удалите строку определения конструктора выше и поместите определение конструктора в определение класса, сделав его встроенной функцией:

// 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, Но это просто, чтобы пролить больше света на проблему; Я не советую вам делать это. Авторы библиотеки должны были бы исправить их код.

Дальнейшее рекомендуемое прочтение: почему защитные устройства не препятствуют определению нескольких функций?


Вот способ воспроизвести ту же проблему с помощью нескольких строк вашего собственного кода:

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++.

Другие вопросы по тегам