Acabo de encontrar el siguiente error (y encontré la solución en línea, pero no está presente en Stack Overflow):
(.gnu.linkonce. [stuff]): referencia indefinida a [método] [archivo de objeto] :(. gnu.linkonce. [stuff]): referencia indefinida a `typeinfo para [classname] '
¿Por qué podría uno obtener uno de estos errores de vinculador "referencia indefinida a typeinfo"?
(Puntos de bonificación si puede explicar lo que sucede detrás de escena).
virtual void abc() =0;
(si la versión base nunca se llama)abc()
así, puede olvidarse fácilmente de redefinirabc()
en la clase derivada y pensar que todo está bien, ya que aún puede llamar a la función sin ningún problema. En este artículo se encuentra una buena práctica para implementar funciones virtuales puras , y esto es hacer que la función imprima "Función virtual pura llamada" y luego bloquee el programa.= 0;
.Respuestas:
Una posible razón es porque está declarando una función virtual sin definirla.
Cuando lo declara sin definirlo en la misma unidad de compilación, está indicando que está definido en otro lugar; esto significa que la fase de enlace intentará encontrarlo en una de las otras unidades de compilación (o bibliotecas).
Un ejemplo de definición de la función virtual es:
En este caso, está adjuntando una definición a la declaración, lo que significa que el vinculador no necesita resolverla más tarde.
La línea
declara
fn()
sin definirlo y provocará el mensaje de error que solicitó.Es muy similar al código:
que establece que el entero
i
se declara en otra unidad de compilación que debe resolverse en el momento del enlace (de lo contrariopi
, no se puede establecer en su dirección).fuente
virtual void fn() = 0
es una definición. No es una definición, sino una mera declaración . La única razón por la que el vinculador no está tratando de resolverlo es porque la entrada VMT correspondiente no se referirá a un cuerpo de función (lo más probable es que contenga un puntero nulo). Sin embargo, nadie le prohíbe llamar a esta función virtual pura de una manera no virtual, es decir, utilizando un nombre totalmente calificado. En este caso, el enlazador se busque el cuerpo, y usted tendrá que definir la función. Y sí, puede definir un cuerpo para una función virtual pura.Esto también puede suceder cuando mezclas
-fno-rtti
y-frtti
codificas. Luego debe asegurarse de que cualquier clase, a la quetype_info
se accede en el-frtti
código, tenga su método clave compilado-frtti
. Tal acceso puede ocurrir cuando crea un objeto de la clase, usadynamic_cast
etc.[ fuente ]
fuente
Esto ocurre cuando las funciones virtuales declaradas (no puras) son cuerpos faltantes. En su definición de clase, algo como:
Debe definirse (en línea o en un archivo fuente vinculado):
O declarado puro virtual:
fuente
Citando del manual de gcc :
Y un poco antes en la misma página:
Entonces, este error ocurre cuando el "método clave" no tiene su definición, como otras respuestas ya mencionadas.
fuente
Si está vinculando un .so a otro, una posibilidad más es compilar con "-fvisibility = hidden" en gcc o g ++. Si ambos archivos .so se compilaron con "-fvisibility = hidden" y el método de la clave no está en el mismo .so que otra de las implementaciones de la función virtual, este último no verá la vtable o typeinfo de la primera. Para el enlazador, esto parece una función virtual no implementada (como en las respuestas de paxdiablo y cdleary).
En este caso, debe hacer una excepción para la visibilidad de la clase base con
en la declaración de clase. Por ejemplo,
Otra solución, por supuesto, es no usar "-visibilidad = oculto". Eso complica las cosas para el compilador y el enlazador, posiblemente en detrimento del rendimiento del código.
fuente
Las respuestas anteriores son correctas, pero este error también puede ser causado al intentar usar typeid en un objeto de una clase que no tiene funciones virtuales. C ++ RTTI requiere una vtable, por lo que las clases en las que desea realizar la identificación de tipo requieren al menos una función virtual.
Si desea que la información de tipo funcione en una clase para la que realmente no desea ninguna función virtual, haga que el destructor sea virtual.
fuente
Acabo de pasar unas horas en este error, y aunque las otras respuestas aquí me ayudaron a comprender lo que estaba sucediendo, no solucionaron mi problema particular.
Estoy trabajando en un proyecto que compila usando ambos
clang++
yg++
. No estaba teniendo problemas de vinculaciónclang++
, pero recibía elundefined reference to 'typeinfo for
errorg++
.El punto importante: vincular el orden IMPORTA con
g++
. Si enumera las bibliotecas que desea vincular en un orden incorrecto, puede obtener eltypeinfo
error.Consulte esta pregunta SO para obtener más detalles sobre el orden de vinculación con
gcc
/g++
.fuente
Posibles soluciones para el código que se ocupa de las bibliotecas RTTI y no RTTI:
a) Vuelva a compilar todo con -frtti o -fno-rtti
b) Si a) no es posible para usted, intente lo siguiente:
Suponga que libfoo está construido sin RTTI. Su código usa libfoo y se compila con RTTI. Si usa una clase (Foo) en libfoo que tiene virtuales, es probable que se encuentre con un error de tiempo de enlace que dice: falta información de tipo para la clase Foo.
Defina otra clase (por ejemplo, FooAdapter) que no tenga virtual y reenviará las llamadas a Foo que utilice.
Compile FooAdapter en una pequeña biblioteca estática que no use RTTI y solo dependa de símbolos libfoo. Proporcione un encabezado y úselo en su código (que usa RTTI). Como FooAdapter no tiene una función virtual, no tendrá ningún tipo de información y podrá vincular su binario. Si usa muchas clases diferentes de libfoo, esta solución puede no ser conveniente, pero es un comienzo.
fuente
De manera similar a la discusión de RTTI, NO-RTTI anterior, este problema también puede ocurrir si usa dynamic_cast y no incluye el código objeto que contiene la implementación de la clase.
Me encontré con este problema al construir en Cygwin y luego portar código a Linux. Los archivos make, la estructura de directorios e incluso las versiones de gcc (4.8.2) fueron idénticos en ambos casos, pero el código se vinculó y funcionó correctamente en Cygwin, pero no se pudo vincular en Linux. Red Hat Cygwin aparentemente ha realizado modificaciones de compilador / enlazador que evitan el requisito de vinculación del código objeto.
El mensaje de error del enlazador de Linux me dirigió correctamente a la línea dynamic_cast, pero los mensajes anteriores en este foro me hicieron buscar implementaciones de funciones que faltan en lugar del problema real: el código de objeto que falta. Mi solución alternativa era sustituir una función de tipo virtual en la clase base y derivada, por ejemplo, virtual int isSpecialType (), en lugar de usar dynamic_cast. Esta técnica evita el requisito de vincular el código de implementación del objeto solo para que dynamic_cast funcione correctamente.
fuente
En la clase base (una clase base abstracta) usted declara un destructor virtual y, como no puede declarar un destructor como una función virtual pura, debe definirlo aquí mismo en la clase abstracta, solo una definición ficticia como virtual ~ base ( ) {} lo hará, o en cualquiera de las clases derivadas.
Si no lo hace, terminará en un "símbolo indefinido" en el momento del enlace. Dado que VMT tiene una entrada para todas las funciones virtuales puras con un NULL coincidente, ya que actualiza la tabla dependiendo de la implementación en la clase derivada. Pero para las funciones no puras pero virtuales, necesita la definición en el momento del enlace para que pueda actualizar la tabla VMT.
Use c ++ filt para demanglear el símbolo. Como $ c ++ filt _ZTIN10storageapi8BaseHostE generará algo como "typeinfo for storageapi :: BaseHost".
fuente
Recibí muchos de estos errores en este momento. Lo que sucedió es que dividí una clase de solo archivo de encabezado en un archivo de encabezado y un archivo cpp. Sin embargo, no actualicé mi sistema de compilación, por lo que el archivo cpp no se compiló. Entre simplemente tener referencias indefinidas a las funciones declaradas en el encabezado pero no implementadas, obtuve muchos de estos errores typeinfo.
La solución fue volver a ejecutar el sistema de compilación para compilar y vincular el nuevo archivo cpp.
fuente
en mi caso, utilicé una biblioteca de terceros con archivos de encabezado y así archivos. Subclasifiqué una clase y se produjo un error de enlace como este cuando intento crear una instancia de mi subclase.
como mencionó @sergiy, sabiendo que podría ser el problema de 'rtti', logré solucionarlo poniendo la implementación del constructor en un archivo .cpp separado y aplicando indicadores de compilación '-fno-rtti' al archivo . funciona bien.
Como todavía no tengo muy claro el error interno de este enlace, no estoy seguro de si mi solución es general. Sin embargo, creo que vale la pena intentarlo antes de probar el adaptador como lo menciona @francois. y, por supuesto, si todos los códigos fuente están disponibles (no en mi caso), mejor compile con '-frtti' si es posible.
Una cosa más, si elige probar mi solución, intente hacer que el archivo separado sea lo más simple posible, y no use algunas características sofisticadas de C ++. preste especial atención a las cosas relacionadas con el impulso, porque gran parte depende de rtti.
fuente
Tengo el mismo error cuando mi interfaz (con todas las funciones virtuales puras) necesitaba una función más y olvidé "anularla".
yo tenía
class ICommProvider { public: /** * @brief If connection is established, it sends the message into the server. * @param[in] msg - message to be send * @return 0 if success, error otherwise */ virtual int vaSend(const std::string &msg) = 0; /** * @brief If connection is established, it is waiting will server response back. * @param[out] msg is the message received from server * @return 0 if success, error otherwise */ virtual int vaReceive(std::string &msg) = 0; virtual int vaSendRaw(const char *buff, int bufflen) = 0; virtual int vaReceiveRaw(char *buff, int bufflen) = 0; /** * @bief Closes current connection (if needed) after serving * @return 0 if success, error otherwise */ virtual int vaClose(); };
El último vaClose no es virtual, por lo que compilado no sabía dónde obtener la implementación y, por lo tanto, se confundió. mi mensaje fue:
Cambio simple de
a
Se solucionó el problema. Espero eso ayude
fuente
Me encuentro con una situación que es rara, pero esto puede ayudar a otros amigos en una situación similar. Tengo que trabajar en un sistema anterior con gcc 4.4.7. Tengo que compilar código con soporte para c ++ 11 o superior, así que construyo la última versión de gcc 5.3.0. Al compilar mi código y vincularme a las dependencias si la dependencia se compila con un compilador más antiguo, recibí un error de 'referencia indefinida a' aunque definí claramente la ruta de enlace con -L / ruta / a / lib -llibname. Algunos paquetes como boost y proyectos compilados con cmake generalmente tienden a usar el compilador anterior, y generalmente causan tales problemas. Tienes que recorrer un largo camino para asegurarte de que usan el compilador más nuevo.
fuente
En mi caso, es puramente un problema de dependencia de la biblioteca, incluso si tengo una llamada dynamic_cast. Después de agregar suficiente dependencia al archivo MAKE, este problema desapareció.
fuente
Compruebe que sus dependencias fueron compiladas sin
-f-nortti
.Para algunos proyectos, debe configurarlo explícitamente, como en RocksDB:
fuente
En mi caso, era una función virtual en una clase de interfaz que no se definía como puramente virtual.
Olvidé la
= 0
parte.fuente