Ошибка множественного определения 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++.