Ошибки компоновщика GCC C++: неопределенная ссылка на 'vtable for XXX', неопределенная ссылка на ' ClassName::ClassName()'
я настраиваю проект C++ на Ubuntu x64, используя Eclipse-CDT. Я в основном делаю Привет мир и ссылки на коммерческую библиотеку 3rd party.
Я включил заголовочные файлы, связанные с их библиотеками, но я все еще получаю ошибки компоновщика. Есть ли какие-то возможные проблемы здесь, кроме очевидных (например, я на 99% уверен, что я ссылаюсь на правильную библиотеку).
- есть ли способ подтвердить статические библиотеки, на которые я ссылаюсь 64bit?
- есть ли способ подтвердить, что библиотека имеет класс (и методы), который я ожидаю от нее?
затмение говорит:
Building target: LinkProblem
Invoking: GCC C++ Linker
g++ -L/home/notroot/workspace/somelib-3/somelib/target/bin -o"LinkProblem" ./src/LinkProblem.o -lsomelib1 -lpthread -lsomelib2 -lsomelib3
./src/LinkProblem.o: In function `main':
/home/notroot/workspace/LinkProblem/Debug/../src/LinkProblem.cpp:17: undefined reference to `SomeClass::close()'
./src/LinkProblem.o: In function `SomeOtherClass':
/home/notroot/workspace/somelib-3/somelib/include/sql/somefile.h:148: undefined reference to `SomeClass::SomeClass()'
/home/notroot/workspace/somelib-3/somelib/include/sql/somefile.h:148: undefined reference to `vtable for SomeOtherClass'
/home/notroot/workspace/somelib-3/somelib/include/sql/somefile.h:151: undefined reference to `SomeClass::~SomeClass()'
./src/LinkProblem.o: In function `~SomeOtherClass':
/home/notroot/workspace/somelib-3/somelib/include/sql/somefile.h:140: undefined reference to `vtable for SomeOtherClass'
/home/notroot/workspace/somelib-3/somelib/include/sql/somefile.h:140: undefined reference to `SomeClass::~SomeClass()'
/home/notroot/workspace/somelib-3/somelib/include/sql/somefile.h:140: undefined reference to `SomeClass::~SomeClass()'
collect2: ld returned 1 exit status
make: *** [LinkProblem] Error 1
12 ответов:
предполагая, что эти методы находятся в одной из библиотек, это выглядит как проблема упорядочения.
при связывании библиотек в исполняемый файл они выполняются в том порядке, в котором они объявлены.
Кроме того, компоновщик будет принимать только методы / функции, необходимые для разрешения текущих незавершенных зависимостей. Если последующая библиотека затем использует методы / функции, которые изначально не требовались объектами, у вас будут отсутствовать зависимости.Как это работает:
- возьмите все объектные файлы и объедините их в исполняемый файл
- разрешить любые зависимости между объектными файлами.
- для каждой библиотеки в порядке:
- Проверьте неразрешенные зависимости и посмотрите, разрешает ли их lib.
- если это так, загрузите необходимую часть в исполняемый файл.
пример:
объекты требуется:
- открыть
- закрыть
- BatchRead
- BatchWrite
Lib 1 обеспечивает:
- открыть
- закрыть
- читать
- написать
Lib 2 обеспечивает
- BatchRead (но использует lib1:read)
- BatchWrite (но использует lib1:write)
Если связано так:
gcc-o plop plop.o-l1-l2
тогда компоновщик не сможет разрешить чтение и запись символов.
но если я свяжу приложение следующим образом:
gcc-o plop plop.o-l2-l1
тогда он будет связываться правильно. Поскольку l2 разрешает зависимости BatchRead и BatchWrite, но также добавляет два новых (чтение и запись). Когда мы связываемся с L1 далее, все четыре зависимости разрешаются.
эта ошибка компоновщика обычно (по моему опыту) означает, что вы переопределили виртуальную функцию в дочернем классе, с декларацией, но не дано определение метода. Например:
class Base { virtual void f() = 0; } class Derived : public Base { void f(); }но вы не дали определение Ф. При использовании класса, вы получите ошибки компоновщика. Как обычная ошибка компоновщика, потому что компилятор знал, о чем вы говорите, но компоновщик не может найти определение. Это просто очень сложно сделать понять сообщение.
Qt C++ покажет эту ошибку при изменении класса таким образом, что он теперь наследует от QObject (т. е. Так, что теперь он может использовать сигналы/слоты). Запуск qmake-r вызовет moc и устранит эту проблему.
Если вы работаете с другими через какой-то контроль версий, вы захотите внести некоторые изменения в свой файл .pro (т. е. добавить/удалить пустую строку). Когда все остальные получат ваши изменения и запустят make, make увидит, что файл .pro изменился и автоматически запускает qmake. Этот спасет ваших товарищей по команде от повторения вашего разочарования.
проблема для меня оказалась довольно неясной. Мой класс выглядел так:
//----------------------------------------- // libbase.h class base { public: base() { } virtual ~base() { } virtual int foo() { return 0; } }; //----------------------------------------- //----------------------------------------- // libbase.cpp #include "libbase.h" //----------------------------------------- //----------------------------------------- // main.h class derived : public base { public: virtual int foo() ; }; //----------------------------------------- //----------------------------------------- // main.cpp int main () { derived d; } //-----------------------------------------проблема в компоновщике. Мой файл заголовка пошел в библиотеку где-то, но все виртуальные функции были объявлены "inline" в объявлении класса. Поскольку не было кода, использующего виртуальные функции (пока), компилятор или компоновщик пренебрегли созданием фактических тел функций. Также не удалось создать таблицу vtable.
в моем основном коде, откуда я получил этот класс, компоновщик попытался подключить Мой класс к базовому классу и его vtable. Но vtable был отброшен.
решение состояло в том, чтобы объявить хотя бы одно из тел виртуальных функций вне объявления класса, например:
//----------------------------------------- // libbase.h class base { public: base() { } virtual ~base() ; //-- No longer declared 'inline' virtual int foo() { return 0; } }; //----------------------------------------- //----------------------------------------- // libbase.cpp #include "libbase.h" base::~base() { } //-----------------------------------------
что касается проблем с Qt4, я не мог использовать опцию qmake moc, упомянутую выше. Но проблема была не в этом. У меня был следующий код в определении класса:
class ScreenWidget : public QGLWidget { Q_OBJECT // must include this if you use Qt signals/slots ... };мне пришлось удалить строку "Q_OBJECT", потому что у меня не было сигналов или слотов, определенных.
У меня это сообщение об ошибке. Проблема заключалась в том, что я объявил виртуальный деструктор в заголовочном файле, но тело виртуальных функций на самом деле не было реализовано.
например:
class Base { virtual void method1(); // throws undefined reference error. }измените приведенное выше объявление на приведенное ниже, оно будет работать нормально.
class Base { virtual void method1() { } }
в моем случае проблема возникла, когда я забыл добавить =0 на одну функцию в моем чистом виртуальном классе. Это было исправлено, когда =0 был добавлен. То же самое, что и для Фрэнка выше.
class ISettings { public: virtual ~ISettings() {}; virtual void OKFunction() =0; virtual void ProblemFunction(); // missing =0 }; class Settings : ISettings { virtual ~Settings() {}; void OKFunction(); void ProblemFunction(); }; void Settings::OKFunction() { //stuff } void Settings::ProblemFunction() { //stuff }
Я тоже наткнулся на этот вопрос. Приложение определило класс чистого виртуального интерфейса, а пользовательский класс, предоставляемый через общую библиотеку, должен был реализовать интерфейс. При связывании приложения компоновщик жаловался, что общая библиотека не предоставляет vtable и type_info для базового класса и не может быть найдена где-либо еще. Оказалось, что я просто забыл сделать один из методов интерфейса чисто виртуальным (т. е. опустил "= 0" в конце декларация. Очень рудиментарно, все еще легко упустить и озадачить, если вы не можете подключить диагностику компоновщика к основной причине.
У меня было это сообщение об ошибке при попытке "hello world", как вещи с Qt. Проблемы исчезли, правильно запустив Qt moc (meta object compiler) и компилируя+, включая эти MOC-сгенерированные файлы правильно.
Если у вас есть базовый класс с чистой виртуальной функцией, убедитесь, что ваш конструктор и деструктор базового класса имеет тело в противном случае компоновщик не работает.
Я поставил это для будущих посетителей:
Если вы получаете сообщение об ошибке при создании
Exceptionобъект, то причиной этого, вероятно, является отсутствие определения дляwhat()виртуальная функция.
Comments