Je viens de rencontrer l'erreur suivante (et j'ai trouvé la solution en ligne, mais elle n'est pas présente dans Stack Overflow):
(.gnu.linkonce. [stuff]): référence non définie à [méthode] [fichier objet] :(. gnu.linkonce. [stuff]): référence non définie à `typeinfo for [classname] '
Pourquoi pourrait-on obtenir l'une de ces erreurs de l'éditeur de liens "référence non définie à typeinfo"?
(Points bonus si vous pouvez expliquer ce qui se passe dans les coulisses.)
virtual void abc() =0;
(si la version de base n'est jamais appelée)abc()
comme ça, vous pouvez facilement oublier de redéfinirabc()
dans la classe dérivée et penser que tout va bien, car vous pourrez toujours appeler la fonction sans aucun problème. Une bonne pratique pour implémenter des fonctions virtuelles pures se trouve dans cet article , et cela consiste à faire en sorte que la fonction affiche "Fonction virtuelle pure appelée", puis plante le programme.= 0;
.Réponses:
Une raison possible est que vous déclarez une fonction virtuelle sans la définir.
Lorsque vous le déclarez sans le définir dans la même unité de compilation, vous indiquez qu'il est défini ailleurs - cela signifie que la phase de l'éditeur de liens essaiera de le trouver dans l'une des autres unités de compilation (ou bibliothèques).
Un exemple de définition de la fonction virtuelle est:
Dans ce cas, vous joignez une définition à la déclaration, ce qui signifie que l'éditeur de liens n'a pas besoin de la résoudre ultérieurement.
La ligne
déclare
fn()
sans le définir et provoquera le message d'erreur que vous avez demandé.Il est très similaire au code:
qui indique que l'entier
i
est déclaré dans une autre unité de compilation qui doit être résolue au moment de la liaison (sinonpi
ne peut pas être définie sur son adresse).la source
virtual void fn() = 0
c'est une définition. Ce n'est pas une définition, mais une simple déclaration . La seule raison pour laquelle l'éditeur de liens n'essaie pas de le résoudre est que l'entrée VMT correspondante ne fera pas référence à un corps de fonction (contiendra probablement un pointeur nul). Cependant, personne ne vous interdit d'appeler cette fonction virtuelle pure de manière non virtuelle, c'est-à-dire en utilisant un nom complet. Dans ce cas , l'éditeur de liens se chercher le corps, et vous devrez définir la fonction. Et oui, vous pouvez définir un corps pour une fonction virtuelle pure.Cela peut également se produire lorsque vous mixez
-fno-rtti
et-frtti
codez. Ensuite, vous devez vous assurer que toute classe, quitype_info
est accessible dans le-frtti
code, a sa méthode clé compilée avec-frtti
. Un tel accès peut se produire lorsque vous créez un objet de la classe, utilisezdynamic_cast
etc.[ source ]
la source
Cela se produit lorsque des fonctions virtuelles déclarées (non pures) manquent de corps. Dans votre définition de classe, quelque chose comme:
Doit être défini (en ligne ou dans un fichier source lié):
Ou déclaré virtuel pur:
la source
Citant du manuel de gcc :
Et un peu plus tôt sur la même page:
Ainsi, cette erreur se produit lorsque la "méthode clé" manque sa définition, comme d'autres réponses déjà mentionnées.
la source
Si vous liez un .so à un autre, une autre possibilité est de compiler avec "-fvisibility = hidden" dans gcc ou g ++. Si les deux fichiers .so ont été créés avec "-fvisibility = hidden" et que la méthode key n'est pas dans le même .so qu'une autre implémentation de la fonction virtuelle, cette dernière ne verra pas la vtable ou typeinfo de la première. Pour l'éditeur de liens, cela ressemble à une fonction virtuelle non implémentée (comme dans les réponses de paxdiablo et cdleary).
Dans ce cas, vous devez faire une exception pour la visibilité de la classe de base avec
dans la déclaration de classe. Par exemple,
Une autre solution, bien sûr, consiste à ne pas utiliser "-fvisibility = hidden". Cela complique les choses pour le compilateur et l'éditeur de liens, peut-être au détriment des performances du code.
la source
Les réponses précédentes sont correctes, mais cette erreur peut également être provoquée en tentant d'utiliser typeid sur un objet d'une classe qui n'a pas de fonctions virtuelles. C ++ RTTI nécessite une table virtuelle, donc les classes sur lesquelles vous souhaitez effectuer l'identification de type nécessitent au moins une fonction virtuelle.
Si vous souhaitez que les informations de type fonctionnent sur une classe pour laquelle vous ne voulez pas vraiment de fonctions virtuelles, rendez le destructeur virtuel.
la source
Je viens de passer quelques heures sur cette erreur, et même si les autres réponses ici m'ont aidé à comprendre ce qui se passait, elles n'ont pas résolu mon problème particulier.
Je travaille sur un projet qui compile en utilisant à la fois
clang++
etg++
. Je n'avais aucun problème de liaison avecclang++
, mais j'obtenais l'undefined reference to 'typeinfo for
erreur avecg++
.Le point important: lier l'ordre MATTERS avec
g++
. Si vous répertoriez les bibliothèques que vous souhaitez lier dans un ordre incorrect, vous pouvez obtenir l'typeinfo
erreur.Voir cette question SO pour plus de détails sur la liaison de la commande avec
gcc
/g++
.la source
Solutions possibles pour le code traitant des bibliothèques RTTI et non RTTI:
a) Recompilez tout avec -frtti ou -fno-rtti
b) Si a) ne vous est pas possible, essayez ce qui suit:
Supposons que libfoo est construit sans RTTI. Votre code utilise libfoo et se compile avec RTTI. Si vous utilisez une classe (Foo) dans libfoo qui a des virtuels, vous risquez de rencontrer une erreur de liaison qui dit: typeinfo manquant pour la classe Foo.
Définissez une autre classe (par exemple, FooAdapter) qui n'a pas de virtuel et transférera les appels à Foo que vous utilisez.
Compilez FooAdapter dans une petite bibliothèque statique qui n'utilise pas RTTI et ne dépend que des symboles libfoo. Fournissez-en un en-tête et utilisez-le à la place dans votre code (qui utilise RTTI). Puisque FooAdapter n'a pas de fonction virtuelle, il n'aura pas de typeinfo et vous pourrez lier votre binaire. Si vous utilisez beaucoup de classes différentes de libfoo, cette solution peut ne pas être pratique, mais c'est un début.
la source
De manière similaire à la discussion RTTI, NO-RTTI ci-dessus, ce problème peut également se produire si vous utilisez dynamic_cast et ne parvenez pas à inclure le code objet contenant l'implémentation de classe.
J'ai rencontré ce problème en construisant sur Cygwin puis en portant du code sur Linux. Les fichiers make, la structure des répertoires et même les versions de gcc (4.8.2) étaient identiques dans les deux cas, mais le code était lié et fonctionnait correctement sur Cygwin mais n'a pas réussi à se lier sur Linux. Red Hat Cygwin a apparemment apporté des modifications au compilateur / éditeur de liens qui évitent l'exigence de liaison du code objet.
Le message d'erreur de l'éditeur de liens Linux m'a correctement dirigé vers la ligne dynamic_cast, mais les messages précédents de ce forum m'ont demandé de rechercher des implémentations de fonctions manquantes plutôt que le problème réel: code d'objet manquant. Ma solution de contournement consistait à remplacer une fonction de type virtuel dans la classe de base et dérivée, par exemple virtual int isSpecialType (), plutôt que d'utiliser dynamic_cast. Cette technique évite l'obligation de lier le code d'implémentation d'objet juste pour que dynamic_cast fonctionne correctement.
la source
Dans la classe de base (une classe de base abstraite), vous déclarez un destructeur virtuel et comme vous ne pouvez pas déclarer un destructeur comme une fonction virtuelle pure, soit vous devez le définir ici dans la classe abstraite, juste une définition fictive comme virtual ~ base ( ) {} fera l'affaire, ou dans n'importe quelle classe dérivée.
Si vous ne le faites pas, vous vous retrouverez dans un "symbole non défini" au moment du lien. Puisque VMT a une entrée pour toutes les fonctions virtuelles pures avec un NULL correspondant car il met à jour la table en fonction de l'implémentation dans la classe dérivée. Mais pour les fonctions non pures mais virtuelles, il a besoin de la définition au moment de la liaison pour pouvoir mettre à jour la table VMT.
Utilisez c ++ filt pour démêler le symbole. Comme $ c ++ filt _ZTIN10storageapi8BaseHostE affichera quelque chose comme "typeinfo pour storageapi :: BaseHost".
la source
J'ai eu beaucoup de ces erreurs tout à l'heure. Ce qui s'est passé, c'est que j'ai divisé une classe de fichiers d'en-tête uniquement en un fichier d'en-tête et un fichier cpp. Cependant, je n'ai pas mis à jour mon système de construction, donc le fichier cpp n'a pas été compilé. Parmi simplement avoir des références non définies aux fonctions déclarées dans l'en-tête mais non implémentées, j'ai eu beaucoup de ces erreurs typeinfo.
La solution consistait à réexécuter le système de génération pour compiler et lier le nouveau fichier cpp.
la source
dans mon cas, j'ai utilisé une bibliothèque tierce avec des fichiers d'en-tête et donc un fichier. j'ai sous-classé une classe, et une erreur de lien comme celle-ci s'est produite lorsque j'essaie d'instancier ma sous-classe.
comme mentionné par @sergiy, sachant que cela pourrait être le problème de 'rtti', j'ai réussi à le contourner en plaçant l'implémentation du constructeur dans un fichier .cpp séparé et en appliquant des indicateurs de compilation '-fno-rtti' au fichier . Ça marche bien.
comme je ne suis pas encore tout à fait clair sur l'interne de cette erreur de lien, je ne sais pas si ma solution est générale. cependant, je pense que ça vaut le coup avant d'essayer l'adaptateur comme mentionné par @francois. et bien sûr, si tous les codes sources sont disponibles (pas dans mon cas), mieux vaut recompiler avec '-frtti' si possible.
une dernière chose, si vous choisissez d'essayer ma solution, essayez de rendre le fichier séparé aussi simple que possible et n'utilisez pas certaines fonctionnalités sophistiquées de C ++. prêter une attention particulière aux choses liées au boost, car cela dépend en grande partie de rtti.
la source
J'ai la même erreur lorsque mon interface (avec toutes les fonctions virtuelles pures) avait besoin d'une fonction de plus et j'ai oublié de la "annuler".
j'ai eu
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(); };
Le dernier vaClose n'est pas virtuel, donc compilé ne savait pas où obtenir l'implémentation et s'est donc perdu. mon message était:
Changement simple de
à
résolu le problème. J'espère que ça aide
la source
Je rencontre une situation rare, mais cela peut aider d'autres amis dans une situation similaire. Je dois travailler sur un ancien système avec gcc 4.4.7. Je dois compiler du code avec le support c ++ 11 ou supérieur, donc je construis la dernière version de gcc 5.3.0. Lors de la construction de mon code et de la liaison aux dépendances si la dépendance est construite avec un compilateur plus ancien, j'ai obtenu l'erreur `` référence non définie à '' même si j'ai clairement défini le chemin de liaison avec -L / chemin / vers / lib -llibname. Certains packages tels que boost et builds avec cmake ont généralement tendance à utiliser l'ancien compilateur, et ils provoquent généralement de tels problèmes. Vous devez faire un long chemin pour vous assurer qu'ils utilisent le nouveau compilateur.
la source
Dans mon cas, c'est purement un problème de dépendance de bibliothèque même si j'ai un appel dynamic_cast. Après avoir ajouté suffisamment de dépendance dans le makefile, ce problème avait disparu.
la source
Vérifiez que vos dépendances ont été compilées sans
-f-nortti
.Pour certains projets, vous devez le définir explicitement, comme dans RocksDB:
la source
Dans mon cas, c'était une fonction virtuelle dans une classe d'interface qui n'était pas définie comme un pur virtuel.
J'ai oublié le
= 0
bit.la source