Ошибки компоновщика GCC C++: неопределенная ссылка на 'vtable for XXX', неопределенная ссылка на ' ClassName::ClassName()'



я настраиваю проект C++ на Ubuntu x64, используя Eclipse-CDT. Я в основном делаю Привет мир и ссылки на коммерческую библиотеку 3rd party.



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




  1. есть ли способ подтвердить статические библиотеки, на которые я ссылаюсь 64bit?

  2. есть ли способ подтвердить, что библиотека имеет класс (и методы), который я ожидаю от нее?


затмение говорит:




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
969   12  

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

    Ничего не найдено.