Qt Linker Error: “referencia no definida a vtable”

Este es mi encabezado:

#ifndef BARELYSOCKET_H #define BARELYSOCKET_H #include  //! 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 reciveMessages; }; #endif // BARELYSOCKET_H 

Esta es mi clase:

 #include  #include  #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) { } 

Obtengo un error de Enlazador:

 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ó.
  • El Message es una struct compleja, pero incluso el uso de int lugar no solucionó las cosas.

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 ejecuta qmake y deberías ser bueno para asumir que no hay otros problemas en tu código.

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

Cuando el comstackdor 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 comstackción, hincha los archivos de objeto y requiere que el enlazador haga más trabajo.

Como una optimización, por lo tanto, los comstackdores elegirán, cuando sea posible, una TU específica para colocar el vtable. En el ABDI común de C ++, esta TU es en la que se implementa la función clave de la clase, donde la función 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 Qt, generalmente comienzan con la macro Q_OBJECT, y esta macro contiene la statement

 virtual const QMetaObject *metaObject() const; 

que, como es la primera función virtual en la macro, generalmente será la primera función virtual de la clase y, por lo tanto, su función clave. Por lo tanto, el comstackdor 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 por moc cuando procesa el encabezado. Por lo tanto, debe tener un proceso moc su encabezado para generar un nuevo archivo .cpp y luego incluir el archivo .cpp en su comstackción.

Entonces, cuando tiene un nuevo encabezado que define una clase derivada de QObject , necesita volver a ejecutar qmake para que actualice sus archivos make para ejecutar moc en el nuevo encabezado y comstackr el archivo .cpp resultante.

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 trabajar durante una hora más o menos, finalmente saqué esa clase de main.cpp y la inserté 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.

Por experiencia: a menudo, un qmake && make clean && make 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.

por cierto. 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)

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

Las señales no deben tener una implementación (esto será generado por Qt). Elimine la implementación de 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.

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 comstackdor. 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.

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

y luego agregó el archivo .cpp y .h. Funciona al fin.

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