2010-03-31 20 views
51

Esta es mi cabecera: Qt Enlazador de error: "referencia indefinida a VTABLE"

#ifndef BARELYSOCKET_H 
#define BARELYSOCKET_H 

#include <QObject> 
//! The First Draw of the BarelySocket! 

class BarelySocket: public QObject 
{ 
    Q_OBJECT 

public: 
    BarelySocket(); 
public slots: 
    void sendMessage(Message aMessage); 
signals: 
    void reciveMessage(Message aMessage); 

private: 
    // QVector<Message> reciveMessages; 
}; 

#endif // BARELYSOCKET_H 

Ésta es mi clase:

#include <QTGui> 
#include <QObject> 
#include "type.h" 
#include "client.h" 
#include "server.h" 

#include "barelysocket.h" 

BarelySocket::BarelySocket() 
{ 
    //this->reciveMessages.clear(); 
    qDebug("BarelySocket::BarelySocket()"); 
} 

void BarelySocket::sendMessage(Message aMessage) 
{ 
} 

void BarelySocket::reciveMessage(Message aMessage) 
{ 
} 

consigo un error del vinculador:

undefined reference to 'vtable for BarelySocket' 
  • Esto implica que tengo un método virtual no implementado. Pero no hay métodos virtuales en mi clase .
  • Comenté el vector pensando que era la causa, pero el error no desapareció.
  • Message es un complejo struct, pero incluso utilizando int en su lugar no solucionó las cosas.
+7

¿Has probado una compilación limpia a partir de ejecutar 'qmake'? Esto puede suceder si 'moc' no procesa el encabezado de su clase por alguna razón. –

+0

Estoy trabajando con QT Creator. Copié todos los archivos cpp en un nuevo Projekt limpio. Eliminé la implementación de la ranura que codifiqué erróneamente. Que los problemas desaparecieron. ¡Gracias por tu ayuda! – Thomas

Respuesta

10

Por experiencia: muchas veces un qmake & & que la limpieza sea & & maquillaje ayuda. Personalmente, percibo que a veces los efectos de detección/caché de cambios/lo que sea-No sé-xxxxx. No puedo decir por qué, pero es lo primero que hago cuando encuentro este tipo de error.

btw. hay un error tipográfico en> recive <

Olvidaste llamar al constructor de QObject en tu constructor (en la lista de inicializadores). (Sin embargo, no resuelve el error)

+5

Esto es especialmente útil cuando el archivo ha existido pero no tenía ninguna referencia Q_OBJECT cuando qmake se ejecutó.Entonces qmake no cree que necesite ejecutar moc y terminas con errores vtable. La limpieza no siempre es necesaria, pero es cuando se realizan ciertos cambios estructurales. –

+4

También asegúrese de que barelysocket.h esté en la sección HEADERS en su archivo pro. – chalup

2

Las señales no deben tener una implementación (Esto será generado por Qt). Elimine la implementación reciveMessage de su archivo .cpp. Esto puede resolver su problema.

Otra cosa que he visto: Dado que la clase BarelySocket hereda de QObject, debe tener un destructor virtual para evitar problemas durante la destrucción. Esto debe hacerse para todas las clases que hereden de otra clase.

+0

Es necesario eliminar la implementación de receiveMessage, pero sería más bien un error de "símbolo definido de forma múltiple". Si la clase base (QObject en este caso) tiene un destructor virtual, los destructores en todas las clases derivadas son automáticamente virtuales. Entonces eso no es un problema aquí. – chalup

12

Me encontré con este error después de crear una pequeña clase dentro de un pequeño archivo "main.cpp" que había creado para probar algo.

Después de futzing durante una hora más o menos, finalmente moví esa clase fuera de main.cpp y en un archivo hpp independiente, actualicé el archivo .pro (proyecto) y el proyecto se construyó perfectamente bien. Puede que ese no haya sido el problema aquí, pero de todos modos pensé que sería una información útil.

+0

¡Hice exactamente el mismo error hoy! También se pierde aproximadamente una hora más o menos ... –

109

Cada vez que agrega una nueva llamada a la macro Q_OBJECT, debe ejecutar qmake nuevamente. El problema de los vtables a los que se refiere está directamente relacionado con eso.

Simplemente ejecute qmake y debería estar listo para asumir que no hay otros problemas en su código.

+16

Dentro de QT Creator, use ejecutar qmake desde el menú Compilar. –

+0

¡Gracias! Desde la línea de comandos, simplemente usar 'make' normalmente también actualiza algunas cosas relacionadas con qmake, pero aparentemente no es suficiente. Ejecutar explícitamente 'qmake' es, de hecho, obligatorio. – Thomas

+0

Ejecutando qmake no es suficiente para mí, tuve que eliminar mi carpeta de compilación y luego volver a compilarla. – PaulrBear

2

Cuando obtiene una clase de QOBject (y utiliza la macro Q_OBJECT), no olvide definir y crear específicamente las clases de constructor y destructor. No es suficiente usar el constructor/destructores predeterminado del compilador. El consejo sobre la limpieza/ejecución de qmake (y la eliminación de sus archivos moc_) aún se aplica. Esto solucionó mi problema similar.

3

Para mí, noté en los registros de compilación que no se llamó a moc.Clean All no ayudó. Así que eliminé .pro.user, reinicié IDE e hice el truco.

26

He visto muchas formas de resolver el problema, pero no hay ninguna explicación de por qué sucede, así que aquí va.

Cuando el compilador ve una clase con funciones virtuales (declaradas directamente o heredadas), debe generar un vtable para esa clase. Dado que las clases generalmente se definen en encabezados (y, por lo tanto, aparecen en varias unidades de traducción), la pregunta es dónde colocar el vtable.

En general, el problema se puede resolver generando el vtable en cada TU donde se define la clase, y luego deje que el vinculador elimine los duplicados. Dado que se requiere que las definiciones de clase sean las mismas en cada aparición por parte de la ODR, esto es seguro. Sin embargo, también ralentiza la compilación, hincha los archivos de objeto y requiere que el enlazador haga más trabajo.

Como una optimización, por lo tanto, los compiladores, cuando sea posible, elige un TU específica para poner la viable. En el común C++ ABI, este TU es aquel en el que función clave de la clase se implementa en, donde la función de clave es la primera función de miembro virtual que se declara en la clase, pero no está definida.

En el caso de las clases de Qt, que por lo general comienzan con la macro Q_OBJECT, y esta macro contiene la declaración

virtual const QMetaObject *metaObject() const; 

el cual, puesto que es la primera función virtual en la macro, en general, será la primera función virtual de la clase y, por lo tanto, su función clave. Por lo tanto, el compilador no emitirá el vtable en la mayoría de las TU, solo la que implementa metaObject. Y la implementación de esta función se escribe automáticamente en moc cuando procesa el encabezado. Por lo tanto, necesita tener moc procesar su encabezado para generar un nuevo archivo .cpp, y luego incluir el archivo .cpp en su compilación.

Así que cuando usted tiene una nueva cabecera que define una clase derivada de QObject, es necesario volver a ejecutar qmake para que se actualice sus archivos make para funcionar moc en la nueva cabecera y compilar el archivo .cpp resultante.

+6

Impresionante reseña. Estoy usando CMake en lugar de qmake, y veo este error con bastante frecuencia; es muy frustrante entender la información básica vtable de C++ y aún no ser capaz de descubrir qué está pasando mal. ¡Gracias! –

+0

@Kyle Strand ¿No debería 'set (CMAKE_AUTOMOC ON)' ser suficiente? Tengo una biblioteca Qt y tengo que ejecutar 'qmake' cada vez para evitar el error vtable. ¿Esto significa que 'cmake' no está ejecutando el' moc' como debería? –

+1

@JamesHirschorn Pensarías que debería ser suficiente, sí. Y de hecho * aparece * que 'moc' se vuelve a ejecutar para cada compilación sin tener en cuenta si los archivos de entrada realmente han cambiado. No estoy seguro de cuál es el problema fundamental de CMake. –

0

Encontré otra razón por la que podría ver esto: dado que qmake analiza los archivos de la clase si los ha modificado de una manera no estándar, puede obtener este error. En mi caso, tenía un cuadro de diálogo personalizado heredado de QDialog, pero solo quería compilarlo y ejecutarlo para construir para Linux, no para Windows ni para OSX. Acabo de enumerar #ifdef __linux__ la clase, por lo que no se compiló, pero en Linux, aunque se definió __linux__, estaba arrojando qmake.

1

Luché con este error horas. Lo resolvió colocando el archivo .cpp y .h en una carpeta separada (!!). Luego añade la carpeta en el archivo .pro: INCLUDEPATH + = $$ _ {} _ PRO_FILE_PWD /../ myclasses/CMyClassWidget

y luego se añadió el .cpp y .h. Funciona al fin.

Cuestiones relacionadas