web-dev-qa-db-fra.com

Erreurs GCC C++ Linker: référence non définie à 'vtable for XXX', référence non définie à 'ClassName :: ClassName ()'

Je configure un projet C++, sur Ubuntu x64, à l'aide d'Eclipse-CDT. En gros, je fais un monde de salut et je me connecte à une bibliothèque tierce commerciale.

J'ai inclus les fichiers d'en-tête, liés à leurs bibliothèques, mais j'obtiens toujours des erreurs de l'éditeur de liens. Existe-t-il des problèmes possibles autres que des problèmes évidents (par exemple, je suis sûr à 99% que je fais un lien vers la bonne bibliothèque).

  1. Existe-t-il un moyen de confirmer que les bibliothèques statiques auxquelles je me connecte sont en 64 bits?
  2. Existe-t-il un moyen de confirmer que la bibliothèque a la classe (et les méthodes) que j'attends?

Eclipse dit:

 Cible de construction: LinkProblem 
 Invocation: GCC C++ Linker 
 G ++ -L/home/notroot/workspace/somelib-3/somelib-cible/bin -o "LinkProblem" ./src/LinkProblem.o - lsomelib1 -lpthread -lsomelib2 -lsomelib3 
./src/LinkProblem.o: Dans la fonction `main ': 
/home/notroot/workspace/LinkProblem/Debug /../ src/LinkProblem.cpp: 17: undefined référence à `SomeClass :: close () '
./src/LinkProblem.o: Dans la fonction` SomeOtherClass': 
/home/notroot/workspace/somelib-3/somelib/include/sql/unfichier.h : 148: référence non définie à `SomeClass :: SomeClass () '
/Home/notroot/workspace/somelib-3/somelib/include/sql/somefile.h: 148: référence non définie à` vtable for SomeOtherClass' 
/home/notroot/workspace/somelib-3/somelib/include/sql/somefile.h:151: référence non définie à `SomeClass :: ~ SomeClass () '. 
./src/LinkProblem.o: Dans la fonction` ~ SomeOtherClass ': 
/Home/notroot/workspace/somelib-3/somelib/include/sql/somefile.h: 140: référence indéfinie à `vtable pour SomeOtherClass' 
/Home/notroot/workspace/somelib- 3/somelib/include/sql/somefile.h: 140: référence indéfinie à `SomeClass :: ~ SomeClass () '
/Home/notroot/workspace/somelib-3/somelib/include/sql/somefile.h: 140: référence indéfinie à 'SomeClass :: ~ SomeClass ()' 
 Collect2: ld a renvoyé 1 état de sortie 
 Make: *** [LinkProblem] Erreur 1 
69
Alex Black

En supposant que ces méthodes soient dans l'une des bibliothèques, cela ressemble à un problème d'ordre.

Lorsque vous liez des bibliothèques à un exécutable, elles sont effectuées dans l'ordre dans lequel elles ont été déclarées.
De plus, l'éditeur de liens ne prendra que les méthodes/fonctions requises pour résoudre les dépendances en suspens. Si une bibliothèque ultérieure utilise ensuite des méthodes/fonctions qui n'étaient pas initialement requises par les objets, vous aurez des dépendances manquantes.

Comment ça marche:

  • Prenez tous les fichiers objets et combinez-les en un exécutable
  • Résolvez les dépendances entre les fichiers objet.
  • Pour chaque bibliothèque dans l'ordre:
    • Vérifiez les dépendances non résolues et voyez si la bibliothèque les résout.
    • Si c'est le cas, chargez la partie requise dans l'exécutable.

Exemple:

Objets nécessite:

  • Ouvrir
  • Fermer 
  • BatchRead
  • BatchWrite

Lib 1 fournit:

  • Ouvrir
  • Fermer
  • lis
  • écrire

Lib 2 fournit

  • BatchRead (mais utilise lib1: read)
  • BatchWrite (mais utilise lib1: write)

Si lié comme ceci:

gcc -o plop plop.o -l1 -l2

Ensuite, l'éditeur de liens ne parviendra pas à résoudre les symboles de lecture et d'écriture.

Mais si je lie l'application comme ceci:

gcc -o plop plop.o -l2 -l1

Ensuite, il sera lié correctement. Comme l2 résout les dépendances BatchRead et BatchWrite mais en ajoute également deux nouvelles (lecture et écriture). Lorsque nous lions avec l1 suivant, les quatre dépendances sont résolues.

73
Martin York

Selon mon expérience, cette erreur de l'éditeur de liens signifie que vous avez remplacé une fonction virtuelle dans une classe enfant par une déclaration, mais vous n'avez pas défini de méthode pour cette méthode. Par exemple:

class Base
{
    virtual void f() = 0;
}
class Derived : public Base
{
    void f();
}

Mais vous n'avez pas donné la définition de f. Lorsque vous utilisez la classe, vous obtenez l'erreur de l'éditeur de liens. Cela ressemble beaucoup à une erreur normale de l'éditeur de liens, car le compilateur savait de quoi vous parliez, mais l'éditeur de liens n'a pas trouvé la définition. C'est juste un message très difficile à comprendre.

168
mgiuca

Qt C++ affiche cette erreur lorsque vous modifiez une classe telle qu'elle hérite maintenant de QObject (c'est-à-dire qu'elle puisse désormais utiliser des signaux/slots). Lancer qmake -r appellera moc et corrigera ce problème. 

Si vous travaillez avec d'autres personnes via un contrôle de version, vous voudrez peut-être modifier votre fichier .pro (par exemple, ajouter/supprimer une ligne vierge). Lorsque tout le monde aura vos modifications et exécute make, make verra que le fichier .pro a été modifié et exécutera automatiquement qmake. Cela évitera à vos coéquipiers de répéter votre frustration.

52
Rick Smith

Le problème pour moi s’est avéré être assez obscur. Ma classe ressemblait à ceci:

//-----------------------------------------
// libbase.h
class base {
public:
   base() { }
   virtual ~base() { }

   virtual int foo() { return 0; }
};
//-----------------------------------------

//-----------------------------------------
// libbase.cpp
#include "libbase.h"
//-----------------------------------------

//-----------------------------------------
// main.h
class derived : public base {
public:
    virtual int foo() ;
};
//-----------------------------------------

//-----------------------------------------
// main.cpp
int main () {
    derived d;
}
//-----------------------------------------

Le problème est dans l'éditeur de liens. Mon fichier d'en-tête est entré dans une bibliothèque quelque part, mais toutes les fonctions virtuelles ont été déclarées 'inline' dans la déclaration de classe. Comme il n'y avait pas encore de code utilisant les fonctions virtuelles, le compilateur ou l'éditeur de liens ont négligé de mettre en place les corps réels des fonctions. Il a également échoué à créer le vtable.

Dans mon code principal où je dérive de cette classe, l'éditeur de liens a tenté de connecter ma classe à la classe de base et à sa vtable. Mais le vtable avait été jeté.

La solution consistait à déclarer au moins un des corps des fonctions virtuelles en dehors de la déclaration de classe, comme ceci:

//-----------------------------------------
// libbase.h
class base {
public:
   base() { }
   virtual ~base() ;   //-- No longer declared 'inline'

   virtual int foo() { return 0; }
};
//-----------------------------------------

//-----------------------------------------
// libbase.cpp
#include "libbase.h"
base::~base() 
{
}
//-----------------------------------------
15
phord

En ce qui concerne les problèmes avec Qt4, je ne pouvais pas utiliser l'option qmake moc mentionnée ci-dessus. Mais ce n'était pas le problème de toute façon. J'ai eu le code suivant dans la définition de la classe:

class ScreenWidget : public QGLWidget
{
   Q_OBJECT        // must include this if you use Qt signals/slots
...
};

J'ai dû supprimer la ligne "Q_OBJECT" car je n'avais pas de signaux ni de créneaux définis.

9
mschachter

J'ai eu ce message d'erreur. Le problème était que j'ai déclaré un destructeur virtuel dans le fichier d'en-tête ,, mais le corps des fonctions virtuelles n'était en réalité pas implémenté.

8
lukeinchina

Cette erreur se produira également lorsque nous déclarons simplement une fonction virtuelle sans définition dans la classe de base.

Par exemple:

class Base
{
    virtual void method1(); // throws undefined reference error.

}

Remplacez la déclaration ci-dessus par celle ci-dessous, cela fonctionnera bien.

class Base
{
    virtual void method1()
    {
    }
}
5
user2376546

Dans mon cas, le problème est survenu lorsque j'ai oublié d’ajouter le = 0 à une fonction de ma classe virtuelle pure. Il a été corrigé lorsque le = 0 a été ajouté. Les mêmes que pour Frank ci-dessus.

class ISettings
{
public: 
    virtual ~ISettings() {};
    virtual void OKFunction() =0;
    virtual void ProblemFunction(); // missing =0   
};

class Settings : ISettings
{
    virtual ~Settings() {};
    void OKFunction();
    void ProblemFunction(); 
};

void Settings::OKFunction()
{
    //stuff
}

void Settings::ProblemFunction()
{
    //stuff
}
4
Lars Persson

Je suis tombé sur la question maintenant, aussi. L'application a défini une classe d'interface virtuelle pure et une classe définie par l'utilisateur fournie via une bibliothèque partagée était supposée implémenter l'interface. En liant l'application, l'éditeur de liens s'est plaint que la bibliothèque partagée ne fournirait pas vtable et type_info pour la classe de base, et ils ne pourraient être trouvés nulle part ailleurs. Il s’est avéré que j’avais simplement oublié de rendre virtuelle l’une des méthodes de l’interface (c’est-à-dire d’omettre le "= 0" à la fin de la déclaration. diagnostic à la cause première.

1
frank

Si vous avez une classe de base avec une fonction virtuelle pure, assurez-vous que le constructeur et le destructeur de la classe de base ont un corps, sinon l'éditeur de liens échoue.

0
sumeet

Je mets ceci pour les futurs visiteurs:

si vous recevez l'erreur lors de la création d'un objet Exception, cela est probablement dû à un manque de définition de la fonction virtuelle what().

0
Mostafa Talebi

J'ai eu ce message d'erreur en essayant "bonjour le monde" comme des choses avec Qt. Les problèmes ont disparu en exécutant correctement qt moc (compilateur d'objet méta) et en compilant + l'inclusion correcte de ces fichiers générés par moc.

0
awallin