c++ - verweis - undefined reference to typeinfo for




g++ undefinierter Verweis auf typeinfo (10)

Ähnlich wie bei der obigen RTTI NO-RTTI-Diskussion kann dieses Problem auch auftreten, wenn Sie dynamic_cast verwenden und den Objektcode mit der Klassenimplementierung nicht einschließen.

Ich stieß auf dieses Problem, das auf Cygwin aufbaut und dann Code zu Linux portierte. Die make-Dateien, die Verzeichnisstruktur und sogar die gcc-Versionen (4.8.2) waren in beiden Fällen identisch, aber der Code war mit Cygwin korrekt verknüpft und funktionierte, konnte jedoch nicht unter Linux verlinkt werden. Red Hat Cygwin hat offenbar Compiler / Linker-Modifikationen vorgenommen, die die Objektcode-Verknüpfungsanforderung vermeiden.

Die Linux-Linker-Fehlermeldung hat mich richtig auf die Zeile dynamic_cast gelenkt, aber frühere Nachrichten in diesem Forum haben mich nach fehlenden Funktionsimplementierungen und nicht nach dem eigentlichen Problem gesucht: fehlender Objektcode. Meine Abhilfe bestand darin, eine virtuelle Typfunktion in der Basis- und abgeleiteten Klasse zu ersetzen, z. B. virtual int isSpecialType (), anstatt dynamic_cast zu verwenden. Diese Technik vermeidet die Notwendigkeit, Objekt-Implementierungscode zu verknüpfen, nur um zu erreichen, dass dynamic_cast ordnungsgemäß funktioniert.

Ich habe gerade den folgenden Fehler (und die Lösung online gefunden, aber es ist nicht in Stack Overflow vorhanden):

(.gnu.linkonce. [stuff]): undefinierter Verweis auf [Methode] [Objektdatei] :(. gnu.linkonce. [stuff]): undefinierter Verweis auf `typeinfo für [Klassenname] '

Warum kann man einen dieser "undefinierten Verweis auf typeinfo" Linker Fehler bekommen?

(Bonuspunkte, wenn Sie erklären können, was hinter den Kulissen passiert.)


Die vorherigen Antworten sind korrekt, aber dieser Fehler kann auch dadurch verursacht werden, dass versucht wird, typeid für ein Objekt einer Klasse zu verwenden, die keine virtuellen Funktionen hat. C ++ RTTI benötigt eine vtable, so dass Klassen, für die Sie eine Typidentifikation durchführen möchten, mindestens eine virtuelle Funktion benötigen.

Wenn Sie möchten, dass Typinformationen für eine Klasse verwendet werden, für die Sie eigentlich keine virtuellen Funktionen möchten, machen Sie den Destruktor virtuell.


Dies tritt auf, wenn deklarierte (nicht reine) virtuelle Funktionen fehlende Körper sind. In Ihrer Klassendefinition etwas wie:

virtual void foo();

Sollte definiert werden (Inline oder in einer verknüpften Quelldatei):

virtual void foo() {}

Oder als rein virtuell deklariert:

virtual void foo() = 0;

Ein möglicher Grund ist, dass Sie eine virtuelle Funktion deklarieren, ohne sie zu definieren.

Wenn Sie es deklarieren, ohne es in der gleichen Kompilierungseinheit zu definieren, geben Sie an, dass es an einer anderen Stelle definiert wurde. Dies bedeutet, dass die Linkerphase versucht, es in einer der anderen Kompilierungseinheiten (oder Bibliotheken) zu finden.

Ein Beispiel für die Definition der virtuellen Funktion ist:

virtual void fn() { /* insert code here */ }

In diesem Fall fügen Sie der Deklaration eine Definition hinzu, was bedeutet, dass der Linker sie später nicht auflösen muss.

Die Linie

virtual void fn();

deklariert fn() ohne es zu definieren und verursacht die Fehlermeldung, nach der Sie gefragt haben.

Es ist dem Code sehr ähnlich:

extern int i;
int *pi = &i;

was besagt, dass die ganze Zahl i in einer anderen Kompilierungseinheit deklariert ist, die zur Verbindungszeit aufgelöst werden muss (andernfalls kann pi nicht auf ihre Adresse gesetzt werden).


Ich habe gerade eine Menge dieser Fehler bekommen. Was passiert ist, ist, dass ich eine Header-Datei-only-Klasse in eine Header-Datei und eine cpp-Datei aufgeteilt habe. Allerdings habe ich mein Build-System nicht aktualisiert, daher wurde die cpp-Datei nicht kompiliert. Unter den einfach nicht definierten Verweisen auf die Funktionen, die im Header deklariert, aber nicht implementiert sind, habe ich viele dieser Typeinfo-Fehler bekommen.

Die Lösung bestand darin, das Build-System erneut auszuführen, um die neue cpp-Datei zu kompilieren und zu verknüpfen.


Ich habe nur ein paar Stunden mit diesem Fehler verbracht, und während die anderen Antworten hier mir geholfen haben, zu verstehen, was vor sich ging, haben sie mein spezielles Problem nicht gelöst.

Ich arbeite an einem Projekt, das mit clang++ und g++ kompiliert. Ich hatte keine Verbindungsprobleme mit clang++ , aber bekam den undefined reference to 'typeinfo for Fehler mit g++ .

Der wichtige Punkt: Verknüpfen Reihenfolge MATTERS mit g++ . Wenn Sie die Bibliotheken typeinfo , die Sie in einer falschen Reihenfolge verknüpfen möchten, können Sie den typeinfo Fehler erhalten.

In dieser SO-Frage finden Sie weitere Informationen zur Verknüpfungsreihenfolge mit gcc / g++ .


In der Basisklasse (eine abstrakte Basisklasse) deklarieren Sie einen virtuellen Destruktor und da Sie einen Destruktor nicht als reine virtuelle Funktion deklarieren können, müssen Sie entweder hier in der abstrakten Klasse definieren, nur eine Dummy-Definition wie virtual ~ base ( ) {} wird tun, oder in irgendeiner der abgeleiteten Klasse.

Wenn Sie dies nicht tun, landen Sie bei der Link-Zeit in einem "undefinierten Symbol". Da VMT einen Eintrag für alle reinen virtuellen Funktionen mit einem übereinstimmenden NULL enthält, wird die Tabelle abhängig von der Implementierung in der abgeleiteten Klasse aktualisiert. Aber für die nicht-reinen, aber virtuellen Funktionen benötigt es die Definition zur Verknüpfungszeit, damit es die VMT-Tabelle aktualisieren kann.

Verwenden Sie c ++ filt, um das Symbol zu minimieren. Wie $ c ++ filt _ZTIN10storageapi8BaseHostE wird so etwas wie "typeinfo für storageapi :: BaseHost" ausgeben.


In meinem Fall habe ich eine Bibliothek von Drittanbietern mit Header-Dateien und so Datei verwendet. Ich unterklassifizierte eine Klasse, und Verbindungsfehler wie dieser trat auf, wenn ich versuche, meine Unterklasse zu instanziieren.

Wie von @sergiy erwähnt, konnte ich das Problem mit 'rtti' umgehen, indem ich die Konstruktorimplementierung in eine separate .cpp-Datei legte und '-fno-rtti' Kompilierflags auf die Datei anwendete . es läuft gut.

Da mir der interne Linkfehler noch nicht ganz klar ist, bin ich mir nicht sicher, ob meine Lösung allgemeingültig ist. Allerdings denke ich, dass es einen Versuch wert ist, bevor ich den Adapter-Weg ausprobiere, wie von @francois erwähnt. und natürlich, wenn alle Quellcodes verfügbar sind (nicht in meinem Fall), sollte man besser mit '-frtti' neu kompilieren, wenn möglich.

Noch eine Sache, wenn Sie versuchen, meine Lösung zu versuchen, versuchen Sie, die separate Datei so einfach wie möglich zu machen, und verwenden Sie nicht einige ausgefallene Funktionen von C ++. achte besonders auf Boost-bezogene Dinge, denn viel davon hängt von rtti ab.


Wenn Sie ein .so mit einem anderen verknüpfen, besteht eine weitere Möglichkeit darin, in gcc oder g ++ mit "-visibility = hidden" zu kompilieren. Wenn beide .so-Dateien mit "-visibility = hidden" erstellt wurden und sich die Schlüsselmethode nicht in derselben .so befindet wie eine andere Implementierung der virtuellen Funktion, sieht die letztere nicht die vtable oder typefinfo der ersten. Für den Linker sieht dies wie eine nicht implementierte virtuelle Funktion aus (wie in den Antworten von paxdiablo und cdleary).

In diesem Fall müssen Sie eine Ausnahme für die Sichtbarkeit der Basisklasse mit machen

__attribute__ ((visibility("default")))

in der Klassendeklaration. Zum Beispiel,

class __attribute__ ((visibility("default"))) boom{
    virtual void stick();
}

Eine andere Lösung ist natürlich, "-visibility = hidden" nicht zu verwenden. Das kompliziert die Dinge für den Compiler und den Linker, möglicherweise auf Kosten der Code-Leistung.


Zitat aus dem gcc-Handbuch :

Bei polymorphen Klassen (Klassen mit virtuellen Funktionen) wird das Objekt type_info zusammen mit der Variablen vtable [...] geschrieben. Bei allen anderen Typen schreiben wir das Objekt type_info aus, wenn es verwendet wird: wenn 'typeid' auf einen Ausdruck angewendet wird, Werfen eines Objekts oder Verweis auf einen Typ in einer Fangklausel oder einer Ausnahmespezifikation.

Und etwas früher auf derselben Seite:

Wenn die Klasse nichtlineare, nicht-reine virtuelle Funktionen deklariert, wird die erste als "Schlüsselmethode" für die Klasse ausgewählt, und die V-Tabelle wird nur in der Übersetzungseinheit ausgegeben, in der die Schlüsselmethode definiert ist.

Dieser Fehler tritt also auf, wenn die "Schlüsselmethode" ihre Definition nicht enthält, wie andere Antworten bereits erwähnt haben.





g++