webentwicklung-frage-antwort-db.com.de

GCC C++ Linker-Fehler: Undefinierte Referenz zu 'vtable for XXX', Undefinierte Referenz zu 'ClassName :: ClassName ()'

Ich stelle ein C++ - Projekt auf Ubuntu x64 mit Eclipse-CDT ein. Ich mache im Grunde eine Hallo-Welt und verlinke mich zu einer kommerziellen Drittanbieter-Bibliothek.

Ich habe die Header-Dateien eingefügt, die mit ihren Bibliotheken verknüpft sind, aber ich erhalte immer noch Linker-Fehler. Gibt es hier andere mögliche Probleme als die offensichtlichen (z. B. bin ich zu 99% sicher, dass ich auf die richtige Bibliothek verlinke).

  1. Gibt es eine Möglichkeit, zu bestätigen, dass die statischen Bibliotheken, zu denen ich verlinkt habe, 64bit sind?
  2. Gibt es eine Möglichkeit, zu bestätigen, dass die Bibliothek die Klasse (und die Methoden) hat, die ich erwarte?

Eclipse sagt:

 Erstellen des Ziels: LinkProblem 
 Aufruf: GCC C++ Linker 
 G ++ -L/home/notroot/workspace/somelib-3/somelib/target/bin -o "LinkProblem" ./src/LinkProblem.o - lsomelib1 -lpthread -lsomelib2 -lsomelib3 
./src/LinkProblem.o: In der Funktion `main ': 
/home/notroot/workspace/LinkProblem/Debug /../ src/LinkProblem.cpp: 17: undefined Verweis auf `SomeClass :: close () '
./src/LinkProblem.o: In der Funktion' SomeOtherClass ': 
/home/notroot/workspace/somelib-3/somelib/include/sql/somefile.h : 148: nicht definierter Verweis auf `SomeClass :: SomeClass () '
/Home/notroot/workspace/somelib-3/somelib/include/sql/somefile.h: 148: nicht definierter Verweis auf` vtable for SomeOtherClass' 
/home/notroot/workspace/somelib-3/somelib/include/sql/somefile.h:151: undefinierter Verweis auf `SomeClass :: ~ SomeClass () '
./src/LinkProblem.o: In Funktion` ~ SomeOtherClass ': 
/Home/notroot/workspace/somelib-3/somelib/include/sql/somefile.h: 140: nicht definierter Verweis auf `vtable für SomeOtherClass' 
/Home/notroot/workspace/somelib- 3/somelib/include/sql/somefile.h: 140: nicht definierter Verweis auf `SomeClass :: ~ SomeClass () '
/Home/notroot/workspace/somelib-3/somelib/include/sql/somefile.h: 140: undefinierter Verweis auf `SomeClass :: ~ SomeClass () '
 Collect2: ld gab den Status 1 zurück 
 Make: *** [LinkProblem] Fehler 1 
69
Alex Black

Angenommen, diese Methoden befinden sich in einer der Bibliotheken, es sieht aus wie ein Problem mit der Reihenfolge.

Wenn Sie Bibliotheken in eine ausführbare Datei verlinken, werden sie in der Reihenfolge ausgeführt, in der sie deklariert sind.
.__ Der Linker verwendet nur die Methoden/Funktionen, die erforderlich sind, um derzeit ausstehende Abhängigkeiten aufzulösen. Wenn eine nachfolgende Bibliothek dann Methoden/Funktionen verwendet, die ursprünglich nicht für die Objekte erforderlich waren, fehlen Abhängigkeiten.

Wie es funktioniert:

  • Nehmen Sie alle Objektdateien und kombinieren Sie sie zu einer ausführbaren Datei
  • Lösen Sie alle Abhängigkeiten zwischen Objektdateien.
  • Für jede Bibliothek in der Reihenfolge:
    • Überprüfen Sie nicht aufgelöste Abhängigkeiten und prüfen Sie, ob die Bibliothek sie löst.
    • Wenn ja, laden Sie den erforderlichen Teil in die ausführbare Datei.

Beispiel:

Objekte erfordert:

  • Öffnen
  • Schließen 
  • BatchRead
  • BatchWrite

Lib 1 bietet:

  • Öffnen
  • Schließen
  • lesen
  • schreiben

Lib 2 bietet

  • BatchRead (verwendet aber lib1: read)
  • BatchWrite (verwendet aber lib1: write)

Wenn so verlinkt:

gcc -o plop plop.o -l1 -l2

Dann löst der Linker die Lese- und Schreibsymbole nicht auf.

Aber wenn ich die Anwendung so verlinke:

gcc -o plop plop.o -l2 -l1

Dann wird es richtig verlinkt. Da l2 die BatchRead- und BatchWrite-Abhängigkeiten auflöst, fügt sie jedoch zwei neue hinzu (Lesen und Schreiben). Wenn wir uns mit l1 verbinden, werden alle vier Abhängigkeiten aufgelöst.

73
Martin York

Dieser Linker-Fehler bedeutet normalerweise (meiner Erfahrung nach), dass Sie eine virtuelle Funktion in einer untergeordneten Klasse mit einer Deklaration überschrieben haben, jedoch keine Definition für die Methode angegeben haben. Zum Beispiel:

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

Aber Sie haben nicht die Definition von f gegeben. Wenn Sie die Klasse verwenden, wird der Linker-Fehler angezeigt. Ähnlich wie bei einem normalen Linker-Fehler, weil der Compiler wusste, worüber Sie sprachen, der Linker jedoch keine Definition fand. Es ist nur eine sehr schwer verständliche Botschaft.

168
mgiuca

Qt C++ zeigt diesen Fehler an, wenn Sie eine Klasse so ändern, dass sie jetzt von QObject erbt (dh, dass sie jetzt Signale/Slots verwenden kann). Das Ausführen von qmake -r ruft moc auf und behebt dieses Problem. 

Wenn Sie über eine Art Versionskontrolle mit anderen Personen arbeiten, sollten Sie einige Änderungen an Ihrer .pro-Datei vornehmen (z. B. eine leere Zeile hinzufügen oder entfernen). Wenn alle anderen Ihre Änderungen erhalten und ausgeführt werden, stellt make fest, dass sich die .pro-Datei geändert hat, und führt automatisch qmake aus. Dies wird Ihre Teamkollegen davon abhalten, Ihre Frustration zu wiederholen.

52
Rick Smith

Das Problem stellte sich für mich als ziemlich dunkel heraus. Meine Klasse sah so aus:

//-----------------------------------------
// 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;
}
//-----------------------------------------

Das Problem liegt im Linker. Meine Header-Datei befand sich irgendwo in einer Bibliothek, aber alle virtuellen Funktionen wurden in der Klassendeklaration als "Inline" deklariert. Da es noch keinen Code gab, der die virtuellen Funktionen verwendete, versäumte der Compiler oder Linker, die eigentlichen Funktionskörper zu implementieren. Die vtable konnte auch nicht erstellt werden.

In meinem Hauptcode, den ich aus dieser Klasse ableitete, versuchte der Linker, meine Klasse mit der Basisklasse und seiner Vtable zu verbinden. Der Tisch war jedoch verworfen worden.

Die Lösung bestand darin, mindestens einen Körper der virtuellen Funktionen außerhalb der Klassendeklaration zu deklarieren:

//-----------------------------------------
// 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

Bei Problemen mit Qt4 konnte ich die oben erwähnte Option "qmake moc" nicht verwenden. Aber das war sowieso nicht das Problem. Ich hatte den folgenden Code in der Klassendefinition:

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

Ich musste die Zeile "Q_OBJECT" entfernen, da ich keine Signale oder Slots definiert hatte.

9
mschachter

Ich hatte diese Fehlermeldung. Das Problem war, dass ich in der Header-Datei einen virtuellen Destruktor deklariert habe, der Körper der virtuellen Funktionen jedoch nicht implementiert wurde.

8
lukeinchina

Dieser Fehler tritt auch auf, wenn wir einfach eine virtuelle Funktion ohne Definition in der Basisklasse deklarieren.

Zum Beispiel:

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

}

Ändern Sie die obige Deklaration in die unten stehende, es funktioniert einwandfrei.

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

In meinem Fall trat das Problem auf, als ich vergaß, in einer reinen virtuellen Klasse = 0 für eine Funktion hinzuzufügen. Es wurde behoben, als die 0 hinzugefügt wurde. Das gleiche wie für Frank oben.

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

Ich bin jetzt auch über das Thema gestolpert. Die Anwendung definierte eine reine virtuelle Schnittstellenklasse, und eine über eine gemeinsam genutzte Bibliothek bereitgestellte benutzerdefinierte Klasse sollte die Schnittstelle implementieren. Beim Verknüpfen der Anwendung beklagte sich der Linker, dass die gemeinsam genutzte Bibliothek weder vtable und type_info für die Basisklasse bereitstellt noch anderweitig gefunden werden kann. Es stellte sich heraus, dass ich einfach vergessen habe, eine der Methoden des Interfaces rein virtuell zu machen (dh das "= 0" am Ende der Deklaration weggelassen. Sehr rudimentär, immer noch leicht zu übersehen und rätselhaft, wenn Sie den Linker nicht verbinden können Diagnose zur Ursache.

1
frank

Wenn Sie eine Basisklasse mit einer reinen virtuellen Funktion haben, stellen Sie sicher, dass der Konstruktor und der Destruktor der Basisklasse über einen Body verfügen, ansonsten schlägt der Linker fehl.

0
sumeet

Ich lege dies für zukünftige Besucher an:

wenn Sie beim Erstellen eines Exception-Objekts den Fehler erhalten, liegt die Ursache wahrscheinlich darin, dass die virtuelle Funktion what() nicht definiert wurde.

0
Mostafa Talebi

Ich hatte diese Fehlermeldung, als ich "Hallo Welt" wie Dinge mit Qt versuchte. Die Probleme wurden behoben, indem der qt moc (Meta-Objekt-Compiler) korrekt ausgeführt und diese Moc-Dateien korrekt kompiliert wurden.

0
awallin