Errores del vinculador C ++ de GCC: referencia no definida a ‘vtable para XXX’, referencia no definida a ‘ClassName :: ClassName ()’

Estoy configurando un proyecto de C ++, en Ubuntu x64, usando Eclipse-CDT. Básicamente estoy haciendo un mundo de saludo y enlazando a una biblioteca comercial de terceros.

He incluido los archivos de encabezado, vinculados a sus bibliotecas, pero todavía tengo errores de enlazador. ¿Hay algunos posibles problemas aquí que no sean los obvios (por ejemplo, estoy 99% seguro de estar enlazando a la biblioteca correcta).

  1. ¿Hay alguna manera de confirmar que las bibliotecas estáticas a las que estoy enlazando son de 64 bits?
  2. ¿Hay alguna forma de confirmar que la biblioteca tiene la clase (y los métodos) que espero que tenga?

Eclipse dice:

 Objetivo de construcción: LinkProblem
 Invocando: 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: en la función `main ':
 /home/notroot/workspace/LinkProblem/Debug/../src/LinkProblem.cpp:17: referencia indefinida a `SomeClass :: close () '
 ./src/LinkProblem.o: en la función `SomeOtherClass ':
 /home/notroot/workspace/somelib-3/somelib/include/sql/somefile.h:148: referencia indefinida a `SomeClass :: SomeClass () '
 /home/notroot/workspace/somelib-3/somelib/include/sql/somefile.h:148: referencia indefinida a `vtable para SomeOtherClass '
 /home/notroot/workspace/somelib-3/somelib/include/sql/somefile.h:151: referencia indefinida a `SomeClass :: ~ SomeClass () '
 ./src/LinkProblem.o: en la función `~ SomeOtherClass ':
 /home/notroot/workspace/somelib-3/somelib/include/sql/somefile.h:140: referencia indefinida a `vtable para SomeOtherClass '
 /home/notroot/workspace/somelib-3/somelib/include/sql/somefile.h:140: referencia indefinida a `SomeClass :: ~ SomeClass () '
 /home/notroot/workspace/somelib-3/somelib/include/sql/somefile.h:140: referencia indefinida a `SomeClass :: ~ SomeClass () '
 collect2: ld devolvió 1 estado de salida
 make: *** [LinkProblem] Error 1

Suponiendo que esos métodos están en una de las libs, parece un problema de pedido.

Al vincular bibliotecas en un archivo ejecutable, se realizan en el orden en que se declaran.
Además, el vinculador solo tomará los métodos / funciones requeridos para resolver las dependencias actualmente pendientes. Si una biblioteca posterior utiliza métodos / funciones que originalmente no eran requeridos por los objetos, faltarán dependencias.

Cómo funciona:

  • Tome todos los archivos de objeto y combínelos en un ejecutable
  • Resuelva cualquier dependencia entre los archivos de objeto.
  • Para cada biblioteca en orden:
    • Verifique las dependencias no resueltas y vea si la lib las resuelve.
    • Si es así, cargue la parte requerida en el ejecutable.

Ejemplo:

Objetos requiere:

  • Abierto
  • Cerca
  • BatchRead
  • BatchWrite

Lib 1 proporciona:

  • Abierto
  • Cerca
  • leer
  • escribir

Lib 2 proporciona

  • BatchRead (pero usa lib1: leer)
  • BatchWrite (pero usa lib1: write)

Si está vinculado así:

gcc -o plop plop.o -l1 -l2

Entonces el enlazador no podrá resolver los símbolos de lectura y escritura.

Pero si enlace la aplicación de esta manera:

gcc -o plop plop.o -l2 -l1

Entonces se vinculará correctamente. Como l2 resuelve las dependencias BatchRead y BatchWrite, pero también agrega dos nuevas (lectura y escritura). Cuando nos vinculamos con l1, las cuatro dependencias se resuelven.

Este error de enlazador generalmente (en mi experiencia) significa que ha anulado una función virtual en una clase secundaria con una statement, pero no ha dado una definición para el método. Por ejemplo:

class Base { virtual void f() = 0; } class Derived : public Base { void f(); } 

Pero no has dado la definición de f. Cuando usas la clase, obtienes el error del enlazador. Al igual que un error de enlazador normal, es porque el comstackdor sabía de lo que estaba hablando, pero el enlazador no pudo encontrar la definición. Simplemente tiene un mensaje muy difícil de entender.

Qt C ++ mostrará este error cuando cambie una clase de modo que ahora herede de QObject (es decir, para que ahora pueda usar señales / ranuras). Al ejecutar qmake -r, se llamará a moc y se solucionará este problema.

Si está trabajando con otros a través de algún tipo de control de versión, querrá hacer algunos cambios en su archivo .pro (es decir, agregar / eliminar una línea en blanco). Cuando todos los demás reciban los cambios y ejecuten make, make verán que el archivo .pro ha cambiado y se ejecutará automáticamente qmake. Esto evitará que tus compañeros repitan tu frustración.

El problema para mí resultó ser bastante oscuro. Mi clase se veía así:

 //----------------------------------------- // 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; } //----------------------------------------- 

El problema está en el enlazador. Mi archivo de encabezado entró en una biblioteca en alguna parte, pero todas las funciones virtuales se declararon ‘en línea’ en la statement de clase. Como no existía un código que utilizara las funciones virtuales (aún), el comstackdor o el vinculador omitieron poner los cuerpos funcionales reales en su lugar. Tampoco se pudo crear el vtable.

En mi código principal, de donde derivaba de esta clase, el enlazador intentó conectar mi clase a la clase base y a su vtable. Pero el vtable había sido descartado.

La solución fue declarar al menos uno de los cuerpos de las funciones virtuales fuera de la statement de clase, así:

 //----------------------------------------- // libbase.h class base { public: base() { } virtual ~base() ; //-- No longer declared 'inline' virtual int foo() { return 0; } }; //----------------------------------------- //----------------------------------------- // libbase.cpp #include "libbase.h" base::~base() { } //----------------------------------------- 

En cuanto a los problemas con Qt4, no pude usar la opción qmake moc mencionada anteriormente. Pero ese no era el problema de todos modos. Tenía el siguiente código en la definición de clase:

 class ScreenWidget : public QGLWidget { Q_OBJECT // must include this if you use Qt signals/slots ... }; 

Tuve que eliminar la línea “Q_OBJECT” porque no tenía señales ni ranuras definidas.

Tuve este mensaje de error. El problema fue que declare un destructor virtual en el archivo de encabezado, pero el cuerpo de las funciones virtuales en realidad no se implementó.

Este error también ocurrirá cuando simplemente declaremos una función virtual sin ninguna definición en la clase base.

Por ejemplo:

 class Base { virtual void method1(); // throws undefined reference error. } 

Cambie la statement anterior a la siguiente, funcionará bien.

 class Base { virtual void method1() { } } 

En mi caso, el problema ocurrió cuando olvidé agregar el = 0 en una función en mi clase virtual pura. Se corrigió cuando se agregó = 0. Lo mismo que para Frank arriba.

 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 } 

Me encontré con el problema ahora, también. La aplicación definía una clase de interfaz virtual pura y se suponía que una clase definida por el usuario proporcionada a través de una biblioteca compartida implementaba la interfaz. Al vincular la aplicación, el vinculador se quejó de que la biblioteca compartida no proporcionaría vtable y type_info para la clase base, ni podría encontrarse en ningún otro lado. Resultó que simplemente olvidé hacer uno de los métodos de la interfaz puramente virtuales (es decir, omití el “= 0” al final de la statement. Muy rudimentario, aún así es fácil pasar por alto y desconcertante si no se puede conectar el diagnóstico del enlazador al causa principal.

Tuve este mensaje de error cuando probaba “hello world” como cosas con Qt. Los problemas desaparecieron ejecutando correctamente el qt moc (comstackdor de metaobjetos) y comstackndo + incluyendo estos archivos generados por moc correctamente.

Si tiene una clase base con función virtual pura, asegúrese de que el constructor y el destructor de su clase base tengan cuerpo, de lo contrario el enlazador falla.

Puse esto para los visitantes futuros:

si está recibiendo el error al crear un objeto Exception , la causa probablemente sea una falta de definición para what() función virtual.