ultima compiler compilador c++ gcc g++

c++ - compiler - gcc ultima version



Referencia indefinida a vtable (27)

Acabo de encontrar otra causa para este error que puedes verificar.

La clase base definió una función virtual pura como:

virtual int foo(int x = 0);

Y la subclase tenía

int foo(int x) override;

El problema fue el error tipográfico que se suponía que el "=0" estaba fuera del paréntesis:

virtual int foo(int x) = 0;

Por lo tanto, en caso de que esté desplazándose hacia abajo, es probable que no haya encontrado la respuesta, esto es algo más que debe verificar.

Así que, estoy recibiendo lo infame horrible

referencia indefinida a ''vtable ...

error para el siguiente código (la clase en cuestión es CGameModule) y no puedo, por mi vida, entender cuál es el problema Al principio, pensé que estaba relacionado con olvidarme de darle un cuerpo a una función virtual, pero hasta donde entiendo, todo está aquí. La cadena de herencia es un poco larga, pero aquí está el código fuente relacionado. No estoy seguro de qué otra información debo proporcionar.

Nota: el constructor es donde está ocurriendo este error, parece.

Mi código:

class CGameModule : public CDasherModule { public: CGameModule(Dasher::CEventHandler *pEventHandler, CSettingsStore *pSettingsStore, CDasherInterfaceBase *pInterface, ModuleID_t iID, const char *szName) : CDasherModule(pEventHandler, pSettingsStore, iID, 0, szName) { g_pLogger->Log("Inside game module constructor"); m_pInterface = pInterface; } virtual ~CGameModule() {}; std::string GetTypedTarget(); std::string GetUntypedTarget(); bool DecorateView(CDasherView *pView) { //g_pLogger->Log("Decorating the view"); return false; } void SetDasherModel(CDasherModel *pModel) { m_pModel = pModel; } virtual void HandleEvent(Dasher::CEvent *pEvent); private: CDasherNode *pLastTypedNode; CDasherNode *pNextTargetNode; std::string m_sTargetString; size_t m_stCurrentStringPos; CDasherModel *m_pModel; CDasherInterfaceBase *m_pInterface; };

Hereda de...

class CDasherModule; typedef std::vector<CDasherModule*>::size_type ModuleID_t; /// /ingroup Core /// @{ class CDasherModule : public Dasher::CDasherComponent { public: CDasherModule(Dasher::CEventHandler * pEventHandler, CSettingsStore * pSettingsStore, ModuleID_t iID, int iType, const char *szName); virtual ModuleID_t GetID(); virtual void SetID(ModuleID_t); virtual int GetType(); virtual const char *GetName(); virtual bool GetSettings(SModuleSettings **pSettings, int *iCount) { return false; }; private: ModuleID_t m_iID; int m_iType; const char *m_szName; };

Que hereda de ....

namespace Dasher { class CEvent; class CEventHandler; class CDasherComponent; }; /// /ingroup Core /// @{ class Dasher::CDasherComponent { public: CDasherComponent(Dasher::CEventHandler* pEventHandler, CSettingsStore* pSettingsStore); virtual ~CDasherComponent(); void InsertEvent(Dasher::CEvent * pEvent); virtual void HandleEvent(Dasher::CEvent * pEvent) {}; bool GetBoolParameter(int iParameter) const; void SetBoolParameter(int iParameter, bool bValue) const; long GetLongParameter(int iParameter) const; void SetLongParameter(int iParameter, long lValue) const; std::string GetStringParameter(int iParameter) const; void SetStringParameter(int iParameter, const std::string & sValue) const; ParameterType GetParameterType(int iParameter) const; std::string GetParameterName(int iParameter) const; protected: Dasher::CEventHandler *m_pEventHandler; CSettingsStore *m_pSettingsStore; }; /// @} #endif


Así que estaba usando Qt con el compilador de Windows XP y MinGW y esto me estaba volviendo loco.

Básicamente, el moc_xxx.cpp se generó vacío incluso cuando me añadieron

Q_OBJECT

Eliminar todo lo que hace que las funciones sean virtuales, explícitas y cualquier cosa que adivines no funcionó. Finalmente comencé a eliminar línea por línea y resultó que tenía

#ifdef something

Alrededor del archivo. Incluso cuando el #ifdef era verdadero, no se generó el archivo moc.

Así que eliminar todos los #ifdefs solucionó el problema.

Esto no estaba pasando con Windows y VS 2013.


Creo que también vale la pena mencionar que también recibirá el mensaje cuando intente vincular al objeto de cualquier clase que tenga al menos un método virtual y el vinculador no pueda encontrar el archivo. Por ejemplo:

Foo.hpp:

class Foo { public: virtual void StartFooing(); };

Foo.cpp:

#include "Foo.hpp" void Foo::StartFooing(){ //fooing }

Compilado con

g++ Foo.cpp -c

Y main.cpp:

#include "Foo.hpp" int main() { Foo foo; }

Compilado y enlazado con:

g++ main.cpp -o main

Da nuestro error favorito:

/tmp/cclKnW0g.o: En la función main'': main.cpp:(.text+0x1a): undefined reference to vtable para Foo'' collect2: error: ld devolvió 1 estado de salida

Esto ocurre desde mi comprensión

  1. Vtable se crea por clase en tiempo de compilación

  2. El enlazador no tiene acceso a vtable que está en Foo.o


El compilador GNU C ++ tiene que tomar una decisión sobre dónde colocar vtable en caso de que tenga la definición de las funciones virtuales de un objeto repartidas en múltiples unidades de compilación (por ejemplo, algunas de las definiciones de funciones virtuales de los objetos están en un archivo .cpp, otras en otro). archivo .cpp, y así sucesivamente).

El compilador elige colocar el vtable en el mismo lugar donde se define la primera función virtual declarada.

Ahora, si por alguna razón se olvidó de proporcionar una definición para esa primera función virtual declarada en el objeto (o se olvidó por error de agregar el objeto compilado en la fase de vinculación), obtendrá este error.

Como efecto secundario, tenga en cuenta que solo para esta función virtual en particular no obtendrá el error tradicional del enlazador, ya que le falta la función foo .


En mi caso, estoy usando Qt y había definido una subclase QObject en un foo.cpp (no .h ). La solución fue agregar #include "foo.moc" al final de foo.cpp .


Entonces, he resuelto el problema y fue una combinación de mala lógica y no estar totalmente familiarizado con el mundo automake / autotools. Estaba agregando los archivos correctos a mi plantilla Makefile.am, pero no estaba seguro de qué paso en nuestro proceso de compilación realmente creó el propio makefile. Entonces, estaba compilando con un viejo makefile que no tenía idea de mis nuevos archivos.

Gracias por las respuestas y el enlace a las preguntas frecuentes de GCC. Me aseguraré de leer eso para evitar que este problema ocurra por una razón real.


Este fue el primer resultado de búsqueda para mí, así que pensé en agregar otra cosa para verificar: asegúrese de que la definición de funciones virtuales esté realmente en la clase. En mi caso, tuve esto:

Archivo de cabecera:

class A { public: virtual void foo() = 0; }; class B : public A { public: void foo() override; };

y en mi archivo .cc:

void foo() { ... }

Esto debería leer

void B::foo() { }


Esto puede suceder con bastante facilidad si olvida enlazar con el archivo objeto que tiene la definición.


Hay mucha especulación en varias respuestas aquí. A continuación le daré un código bastante mínimo que reproduce este error y explicaré por qué está ocurriendo.

Código bastante mínimo para reproducir este error

IBase.hpp

#pragma once class IBase { public: virtual void action() = 0; };

Derived.hpp

#pragma once #include "IBase.hpp" class Derived : public IBase { public: Derived(int a); void action() override; };

Derived.cpp

#include "Derived.hpp" Derived::Derived(int a) { } void Derived::action() {}

myclass.cpp

#include <memory> #include "Derived.hpp" class MyClass { public: MyClass(std::shared_ptr<Derived> newInstance) : instance(newInstance) { } void doSomething() { instance->action(); } private: std::shared_ptr<Derived> instance; }; int main(int argc, char** argv) { Derived myInstance(5); MyClass c(std::make_shared<Derived>(myInstance)); c.doSomething(); return 0; }

Puedes compilar esto usando GCC de esta manera:

g++ -std=c++11 -o a.out myclass.cpp Derived.cpp

Ahora puede reproducir el error eliminando = 0 en IBase.hpp. Me sale este error:

~/.../catkin_ws$ g++ -std=c++11 -o /tmp/m.out /tmp/myclass.cpp /tmp/Derived.cpp /tmp/cclLscB9.o: In function `IBase::IBase(IBase const&)'': myclass.cpp:(.text._ZN5IBaseC2ERKS_[_ZN5IBaseC5ERKS_]+0x13): undefined reference to `vtable for IBase'' /tmp/cc8Smvhm.o: In function `IBase::IBase()'': Derived.cpp:(.text._ZN5IBaseC2Ev[_ZN5IBaseC5Ev]+0xf): undefined reference to `vtable for IBase'' /tmp/cc8Smvhm.o:(.rodata._ZTI7Derived[_ZTI7Derived]+0x10): undefined reference to `typeinfo for IBase'' collect2: error: ld returned 1 exit status

Explicación

Tenga en cuenta que el código anterior no requiere destructores virtuales, constructores ni ningún otro archivo adicional para que la compilación sea exitosa (aunque debería tenerlos).

La forma de entender este error es la siguiente: Linker está buscando un constructor de IBase. Este lo necesitará para el constructor de Derivado. Sin embargo, como Derivados reemplaza los métodos de IBase, tiene una tabla adjunta que hará referencia a IBase. Cuando el enlazador dice "referencia indefinida a vtable para IBase", básicamente significa que Derived tiene una referencia vtable a IBase pero no puede encontrar ningún código de objeto compilado de IBase para consultar. Así que la conclusión es que la clase IBase tiene declaraciones sin implementaciones. Esto significa que un método en IBase se declara como virtual, pero se nos olvidó marcarlo como virtual puro O proporcionar su definición.

Consejo de despedida

Si todo lo demás falla, entonces una forma de depurar este error es compilar un programa mínimo que compile y luego seguir cambiándolo para que llegue al estado que desea. En el medio, sigue compilando para ver cuándo comienza a fallar.

Nota sobre el sistema de construcción ROS y Catkin.

Si estaba compilando el conjunto anterior de clases en ROS usando el sistema de compilación de Catkin, entonces necesitará las siguientes líneas en CMakeLists.txt:

add_executable(myclass src/myclass.cpp src/Derived.cpp) add_dependencies(myclass theseus_myclass_cpp) target_link_libraries(myclass ${catkin_LIBRARIES})

La primera línea básicamente dice que queremos hacer un ejecutable llamado myclass y el código para compilar esto se puede encontrar en los siguientes archivos. Uno de estos archivos debe tener main (). Tenga en cuenta que no tiene que especificar archivos .hpp en ningún lugar de CMakeLists.txt. Además, no tiene que especificar Derived.cpp como biblioteca.


Hay muchas posibilidades mencionadas para causar este error, y estoy seguro de que muchas de ellas causan el error. En mi caso, hubo otra definición de la misma clase, debido a una duplicación del archivo fuente. Este archivo se compiló, pero no se vinculó, por lo que el vinculador se quejaba de no poder encontrarlo.

Para resumir, diría que si ha mirado a la clase el tiempo suficiente y no puede ver qué problema de sintaxis podría estar causando, busque problemas de compilación como un archivo faltante o un archivo duplicado.


La referencia indefinida a vtable también puede ocurrir debido a la siguiente situación. Solo prueba esto:

La clase A contiene:

virtual void functionA(parameters)=0; virtual void functionB(parameters);

La clase B contiene:

  1. La definición de la función antedicha.
  2. La definición de la función B anterior.

La Clase C contiene: ahora está escribiendo una Clase C en la que la derivará de la Clase A.

Ahora, si intenta compilar, obtendrá una referencia indefinida a vtable para la Clase C como error.

Razón:

functionA se define como virtual puro y su definición se proporciona en la Clase B. functionB se define como virtual (NO PURO VIRTUAL) por lo que intenta encontrar su definición en la Clase A, pero usted proporcionó su definición en la Clase B.

Solución:

  1. Haga que la función B sea pura virtual (si tiene un requisito como ese) virtual void functionB(parameters) =0; (Esto funciona está probado)
  2. Proporcione la definición de functionB en la Clase A manteniéndola como virtual. (Espero que funcione ya que no probé esto)

Las preguntas frecuentes de GCC tienen una entrada:

La solución es asegurar que todos los métodos virtuales que no son puros estén definidos. Tenga en cuenta que un destructor debe definirse incluso si se declara pure-virtual [class.dtor] / 7.


No para cruzar post pero. Si se trata de herencia, el segundo hit de Google fue lo que había perdido, es decir. Todos los métodos virtuales deben ser definidos.

Como:

virtual void fooBar() = 0;

Consulte la referencia indeware C ++ Undefined a vtable y herencia para obtener más detalles. Acabo de darme cuenta de que ya se mencionó anteriormente, pero puede ayudar a alguien.


Obtuve este tipo de error en situaciones en las que intentaba enlazar con un objeto cuando recibí un error de creación que impedía que el objeto se agregara al archivo.

Digamos que tengo libXYZ.a que se supone que tiene bioseq.o en int pero no lo hace.

Tengo un error:

combineseq.cpp:(.text+0xabc): undefined reference to `vtable for bioseq''

Esto es bastante diferente de todo lo anterior. Llamaría a este objeto faltante en el problema de archivo.


Ok, la solución a esto es que puedes haberte perdido la definición. Vea el ejemplo a continuación para evitar el error del compilador vtable:

// In the CGameModule.h class CGameModule { public: CGameModule(); ~CGameModule(); virtual void init(); }; // In the CGameModule.cpp #include "CGameModule.h" CGameModule::CGameModule() { } CGameModule::~CGameModule() { } void CGameModule::init() // Add the definition { }


Para lo que vale la pena, olvidando un cuerpo en un destructor virtual genera lo siguiente:

referencia indefinida a `vtable para CYourClass ''.

Estoy agregando una nota porque el mensaje de error es engañoso. (Esto fue con gcc versión 4.6.3.)


Recibí este error cuando agregué una segunda clase a un par de fuente / encabezado existente. Dos encabezados de clase en el mismo archivo .h, y definiciones de funciones para dos clases en el mismo archivo .cpp.

He hecho esto con éxito antes, con clases que están destinadas a trabajar en estrecha colaboración, pero al parecer, esta vez no me gustó. Aún no sé qué, pero dividirlos en una clase por unidad de compilación lo solucionó de inmediato.

El intento fallido:

_gui_icondata.h:

#ifndef ICONDATA_H #define ICONDATA_H class Data; class QPixmap; class IconData { public: explicit IconData(); virtual ~IconData(); virtual void setData(Data* newData); Data* getData() const; virtual const QPixmap* getPixmap() const = 0; void toggleSelected(); void toggleMirror(); virtual void updateSelection() = 0; virtual void updatePixmap(const QPixmap* pixmap) = 0; protected: Data* myData; }; //-------------------------------------------------------------------------------------------------- #include "_gui_icon.h" class IconWithData : public Icon, public IconData { Q_OBJECT public: explicit IconWithData(QWidget* parent); virtual ~IconWithData(); virtual const QPixmap* getPixmap() const; virtual void updateSelection(); virtual void updatePixmap(const QPixmap* pixmap); signals: public slots: }; #endif // ICONDATA_H

_gui_icondata.cpp:

#include "_gui_icondata.h" #include "data.h" IconData::IconData() { myData = 0; } IconData::~IconData() { if(myData) { myData->removeIcon(this); } //don''t need to clean up any more; this entire object is going away anyway } void IconData::setData(Data* newData) { if(myData) { myData->removeIcon(this); } myData = newData; if(myData) { myData->addIcon(this, false); } updateSelection(); } Data* IconData::getData() const { return myData; } void IconData::toggleSelected() { if(!myData) { return; } myData->setSelected(!myData->getSelected()); updateSelection(); } void IconData::toggleMirror() { if(!myData) { return; } myData->setMirrored(!myData->getMirrored()); updateSelection(); } //-------------------------------------------------------------------------------------------------- IconWithData::IconWithData(QWidget* parent) : Icon(parent), IconData() { } IconWithData::~IconWithData() { } const QPixmap* IconWithData::getPixmap() const { return Icon::pixmap(); } void IconWithData::updateSelection() { } void IconWithData::updatePixmap(const QPixmap* pixmap) { Icon::setPixmap(pixmap, true, true); }

Una vez más, agregar un nuevo par de fuente / encabezado y cortar / pegar la clase IconWithData literalmente allí "simplemente funcionó".


Recibí este error solo porque el nombre de un argumento de constructor difería en el archivo de encabezado y en el archivo de implementación. La firma del constructor es

PointSet (const PointSet & pset, Parent * parent = 0);

Y lo que escribí en la implementación comenzó con

PointSet (const PointSet & pest, Parent * parent)

por lo tanto, accidentalmente reemplace "pset" con "plaga". El compilador se quejaba de este y otros dos constructores en los que no había ningún error. Estoy usando g ++ versión 4.9.1 bajo Ubuntu. Y la definición de un destructor virtual en esta clase derivada no hizo ninguna diferencia (se define en la clase base). Nunca hubiera encontrado este error si no hubiera pegado los cuerpos de los constructores en el archivo de encabezado, definiéndolos así en clase.


Si está utilizando Qt, intente volver a ejecutar qmake. Si este error está en la clase del widget, qmake podría no haber notado que el ui class vtable debería regenerarse. Esto solucionó el problema para mí.


Si todo lo demás falla, busca la duplicación. Fui mal dirigido por la referencia inicial explícita a los constructores y destructores hasta que leí una referencia en otro post. Es cualquier método sin resolver. En mi caso, pensé que había reemplazado la declaración que usaba char * xml como parámetro con una que usaba el const char * xml innecesariamente molesto, pero en cambio, había creado una nueva y dejé la otra en su lugar.


Simplemente recibí este error porque mi archivo cpp no ​​estaba en el archivo make.


Tal vez faltar el destructor virtual sea factor contribuyente?

virtual ~CDasherModule(){};


Tal vez no Definitivamente ~CDasherModule() {} .


También es posible que reciba un mensaje como

SomeClassToTest.host.o: In function `class1::class1(std::string const&)'': class1.hpp:114: undefined reference to `vtable for class1'' SomeClassToTest.host.o: In function `class1::~class1()'': class1.hpp:119: undefined reference to `vtable for class1'' collect2: error: ld returned 1 exit status [link] FAILED: ''g++'' ''-o'' ''stage/tests/SomeClassToTest'' ''object/tests/SomeClassToTest.host.o'' ''object/tests/FakeClass1.SomeClassToTest.host.o''

si olvida definir una función virtual de una clase FakeClass1 cuando intenta vincular una prueba de unidad para otra clase SomeClass.

//class declaration in class1.h class class1 { public: class1() { } virtual ~class1() { } virtual void ForgottenFunc(); };

Y

//class definition in FakeClass1.h //... //void ForgottenFunc() {} is missing here

En este caso, te sugiero que revises tu falso para class1 una vez más. Probablemente encontrará que puede haber olvidado definir una función virtual ForgottenFunc en su clase falsa.


Tantas respuestas aquí, pero ninguna de ellas parecía haber cubierto cuál era mi problema. Tuve los siguientes:

class I { virtual void Foo()=0; };

Y en otro archivo (incluido en la compilación y enlace, por supuesto).

class C : public I{ void Foo() { //bar } };

Bueno, esto no funcionó y recibí el error del que todos están hablando. Para resolverlo, tuve que mover la definición real de Foo fuera de la declaración de clase como tal:

class C : public I{ void Foo(); }; C::Foo(){ //bar }

No soy un gurú de C ++, así que no puedo explicar por qué esto es más correcto, pero resolvió el problema por mí.


Tengo este error en el siguiente escenario

Considere un caso en el que haya definido la implementación de funciones miembro de una clase en el propio archivo de encabezado. Este archivo de encabezado es un encabezado exportado (en otras palabras, podría copiarse a algún común / incluir directamente en su base de código). Ahora ha decidido separar la implementación de las funciones miembro en el archivo .cpp. Después de separar / mover la implementación a .cpp, el archivo de encabezado ahora tiene solo los prototipos de las funciones miembro dentro de la clase. Después de los cambios anteriores, si construye su base de código, puede obtener el error "referencia indefinida a ''vtable ...".

Para solucionar esto, antes de construir, asegúrese de eliminar el archivo de encabezado (en el que realizó los cambios) en el directorio común / incluir. También asegúrese de cambiar su archivo make para acomodar / agregar el nuevo archivo .o que se crea a partir del nuevo archivo .cpp que acaba de crear. Cuando realice estos pasos, el compilador / enlazador ya no se quejará.


  • ¿Estás seguro de que CDasherComponent tiene un cuerpo para el destructor? Definitivamente no está aquí, la pregunta es si está en el archivo .cc.
  • Desde una perspectiva de estilo, CDasherModule debe definir explícitamente su destructor virtual .
  • Parece que CGameModule tiene un extra } al final (después de }; // for the class ).
  • ¿ CGameModule está vinculado con las bibliotecas que definen CDasherModule y CDasherComponent ?