Beim Erstellen meines C ++ - Programms wird die Fehlermeldung angezeigt
undefinierter Verweis auf 'vtable ...
Was ist die Ursache für dieses Problem? Wie behebe ich das?
Es kommt also vor, dass ich den Fehler für den folgenden Code erhalte (die fragliche Klasse ist CGameModule.) Und ich kann für mein ganzes Leben nicht verstehen, wo das Problem liegt. Zuerst dachte ich, es würde damit zusammenhängen, zu vergessen, einer virtuellen Funktion einen Körper zu geben, aber soweit ich verstehe, ist alles hier. Die Vererbungskette ist etwas lang, aber hier ist der zugehörige Quellcode. Ich bin mir nicht sicher, welche anderen Informationen ich bereitstellen soll.
Hinweis: Im Konstruktor tritt dieser Fehler anscheinend auf.
Mein Code:
class CGameModule : public CDasherModule {
public:
CGameModule(Dasher::CEventHandler *pEventHandler, CSettingsStore *pSettingsStore, CDasherInterfaceBase *pInterface, ModuleID_t iID, const char *szName)
: CDasherModule(pEventHandler, pSettingsStore, iID, 0, szName)
{
g_pLogger->Log("Inside game module constructor");
m_pInterface = pInterface;
}
virtual ~CGameModule() {};
std::string GetTypedTarget();
std::string GetUntypedTarget();
bool DecorateView(CDasherView *pView) {
//g_pLogger->Log("Decorating the view");
return false;
}
void SetDasherModel(CDasherModel *pModel) { m_pModel = pModel; }
virtual void HandleEvent(Dasher::CEvent *pEvent);
private:
CDasherNode *pLastTypedNode;
CDasherNode *pNextTargetNode;
std::string m_sTargetString;
size_t m_stCurrentStringPos;
CDasherModel *m_pModel;
CDasherInterfaceBase *m_pInterface;
};
Erbt von ...
class CDasherModule;
typedef std::vector<CDasherModule*>::size_type ModuleID_t;
/// \ingroup Core
/// @{
class CDasherModule : public Dasher::CDasherComponent {
public:
CDasherModule(Dasher::CEventHandler * pEventHandler, CSettingsStore * pSettingsStore, ModuleID_t iID, int iType, const char *szName);
virtual ModuleID_t GetID();
virtual void SetID(ModuleID_t);
virtual int GetType();
virtual const char *GetName();
virtual bool GetSettings(SModuleSettings **pSettings, int *iCount) {
return false;
};
private:
ModuleID_t m_iID;
int m_iType;
const char *m_szName;
};
Welches erbt von ....
namespace Dasher {
class CEvent;
class CEventHandler;
class CDasherComponent;
};
/// \ingroup Core
/// @{
class Dasher::CDasherComponent {
public:
CDasherComponent(Dasher::CEventHandler* pEventHandler, CSettingsStore* pSettingsStore);
virtual ~CDasherComponent();
void InsertEvent(Dasher::CEvent * pEvent);
virtual void HandleEvent(Dasher::CEvent * pEvent) {};
bool GetBoolParameter(int iParameter) const;
void SetBoolParameter(int iParameter, bool bValue) const;
long GetLongParameter(int iParameter) const;
void SetLongParameter(int iParameter, long lValue) const;
std::string GetStringParameter(int iParameter) const;
void SetStringParameter(int iParameter, const std::string & sValue) const;
ParameterType GetParameterType(int iParameter) const;
std::string GetParameterName(int iParameter) const;
protected:
Dasher::CEventHandler *m_pEventHandler;
CSettingsStore *m_pSettingsStore;
};
/// @}
#endif
qmake -project
und dannqmake
) nicht neu erstellt haben, um eine neue zu generierenMakefile
, ist dies eine wahrscheinliche Fehlerquelle bei der Verwendung von Qt.Q_OBJECT
extern kopiert wird, aber noch nicht Teil der .pro-Datei ist, sie zwar gut kompiliert wird, aber keine Verknüpfung besteht. Wir müssen diese.h/.cpp
Datei in die .pro-Datei einfügen, um dies zu könnenqmake
.Antworten:
Die GCC-FAQ enthält einen Eintrag:
quelle
nm -C CGameModule.o | grep CGameModule::
listet die definierten Methoden auf, vorausgesetzt, Ihre gesamte Klassenimplementierung wird in die logische Objektdatei aufgenommen. Sie können dies mit dem vergleichen, was als virtuell definiert ist, um herauszufinden, was Sie verpasst haben.Für das, was es wert ist, erzeugt das Vergessen eines Körpers auf einem virtuellen Destruktor Folgendes:
Ich füge eine Notiz hinzu, weil die Fehlermeldung täuscht. (Dies war mit gcc Version 4.6.3.)
quelle
~Destructor = default;
in der Header-Datei hat nicht geholfen. Gibt es einen dokumentierten Fehler gegen gcc?Also habe ich das Problem herausgefunden und es war eine Kombination aus schlechter Logik und nicht ganz vertraut mit der Welt der Automake / Autotools. Ich habe meiner Makefile.am-Vorlage die richtigen Dateien hinzugefügt, war mir aber nicht sicher, in welchem Schritt unseres Erstellungsprozesses das Makefile selbst erstellt wurde. Also habe ich mit einem alten Makefile kompiliert, das überhaupt keine Ahnung von meinen neuen Dateien hatte.
Vielen Dank für die Antworten und den Link zu den GCC-FAQ. Ich werde das sicher lesen, um zu vermeiden, dass dieses Problem aus einem echten Grund auftritt.
quelle
Wenn Sie Qt verwenden, versuchen Sie, qmake erneut auszuführen. Wenn sich dieser Fehler in der Klasse des Widgets befindet, hat qmake möglicherweise nicht bemerkt, dass die vtable der UI-Klasse neu generiert werden sollte. Dies hat das Problem für mich behoben.
quelle
qmake
, ich hatte das gleiche mitcmake
. Ein Teil des Problems könnte sein, dass beide Tools ein Problem mit Header-Dateien haben, das bei Bedarf möglicherweise nicht immer eine Neuerstellung auslöst.Ein undefinierter Verweis auf vtable kann auch aufgrund der folgenden Situation auftreten. Versuchen Sie einfach Folgendes:
Klasse A enthält:
Klasse B enthält:
Klasse C enthält: Jetzt schreiben Sie eine Klasse C, in der Sie sie aus Klasse A ableiten werden.
Wenn Sie nun versuchen zu kompilieren, erhalten Sie als Fehler einen undefinierten Verweis auf vtable für Klasse C.
Grund:
functionA
wird als rein virtuell definiert und seine Definition wird in Klasse B bereitgestellt.functionB
wird als virtuell definiert (NICHT PURE VIRTUAL), sodass versucht wird, seine Definition in Klasse A selbst zu finden, aber Sie haben seine Definition in Klasse B angegeben.Lösung:
virtual void functionB(parameters) =0;
(Dies funktioniert, es wird getestet)quelle
Ich habe diesen Fehler einfach erhalten, weil meine CPP-Datei nicht im Makefile war.
quelle
undefined reference to {function/class/struct}
wenn es umvirtual
Dinge geht. Warf mich ab.Was ist ein
vtable
?Es kann hilfreich sein, zu wissen, worüber die Fehlermeldung spricht, bevor Sie versuchen, sie zu beheben. Ich werde auf einem hohen Niveau beginnen und dann auf einige weitere Details eingehen. Auf diese Weise können Benutzer überspringen, sobald sie mit dem Verständnis von vtables vertraut sind. … Und da springen gerade eine Menge Leute voran. :) Für diejenigen, die hier bleiben:
Eine vtable ist im Grunde die häufigste Implementierung von Polymorphismus in C ++ . Wenn vtables verwendet werden, hat jede polymorphe Klasse irgendwo im Programm eine vtable. Sie können es sich als (verstecktes)
static
Datenelement der Klasse vorstellen. Jedes Objekt einer polymorphen Klasse ist der vtable für die am meisten abgeleitete Klasse zugeordnet. Durch Überprüfen dieser Zuordnung kann das Programm seine polymorphe Magie entfalten. Wichtige Einschränkung: Eine vtable ist ein Implementierungsdetail. Es wird vom C ++ - Standard nicht vorgeschrieben, obwohl die meisten (alle?) C ++ - Compiler vtables verwenden, um polymorphes Verhalten zu implementieren. Die Details, die ich präsentiere, sind entweder typische oder vernünftige Ansätze. Compiler dürfen davon abweichen!Jedes polymorphe Objekt hat einen (versteckten) Zeiger auf die vtable für die am meisten abgeleitete Klasse des Objekts (in den komplexeren Fällen möglicherweise mehrere Zeiger). Durch Betrachten des Zeigers kann das Programm den "echten" Typ eines Objekts erkennen (außer während der Konstruktion, aber lassen Sie uns diesen Sonderfall überspringen). Wenn beispielsweise ein Objekt vom Typ
A
nicht auf die vtable von verweistA
, ist dieses Objekt tatsächlich ein Unterobjekt von etwas, von dem abgeleitet wurdeA
.Der Name „VTable“ kommt von „ v irtual Funktion Tabelle “. In dieser Tabelle werden Zeiger auf (virtuelle) Funktionen gespeichert. Ein Compiler wählt seine Konvention für die Anordnung der Tabelle. Ein einfacher Ansatz besteht darin, die virtuellen Funktionen in der Reihenfolge zu durchlaufen, in der sie in den Klassendefinitionen deklariert sind. Wenn eine virtuelle Funktion aufgerufen wird, folgt das Programm dem Zeiger des Objekts auf eine vtable, geht zu dem Eintrag, der der gewünschten Funktion zugeordnet ist, und verwendet dann den gespeicherten Funktionszeiger, um die richtige Funktion aufzurufen. Es gibt verschiedene Tricks, um diese Arbeit zu machen, aber ich werde hier nicht darauf eingehen.
Wo / wann wird ein
vtable
generiert?Eine vtable wird vom Compiler automatisch generiert (manchmal als "emittiert" bezeichnet). Ein Compiler könnte in jeder Übersetzungseinheit, die eine polymorphe Klassendefinition sieht, eine vtable ausgeben, aber das wäre normalerweise ein unnötiger Overkill. Eine Alternative ( von gcc und wahrscheinlich von anderen verwendet) besteht darin, eine einzelne Übersetzungseinheit auszuwählen, in der die vtable platziert werden soll, ähnlich wie Sie eine einzelne Quelldatei auswählen würden, in die die statischen Datenelemente einer Klasse eingefügt werden sollen. Wenn bei diesem Auswahlprozess keine Übersetzungseinheiten ausgewählt werden, wird die vtable zu einer undefinierten Referenz. Daher der Fehler, dessen Botschaft zugegebenermaßen nicht besonders klar ist.
In ähnlicher Weise wird die vtable zu einer undefinierten Referenz, wenn der Auswahlprozess eine Übersetzungseinheit auswählt, diese Objektdatei jedoch nicht für den Linker bereitgestellt wird. Leider kann die Fehlermeldung in diesem Fall noch weniger deutlich sein als in dem Fall, in dem der Auswahlprozess fehlgeschlagen ist. (Vielen Dank an die Antwortenden, die diese Möglichkeit erwähnt haben. Ich hätte es sonst wahrscheinlich vergessen.)
Der von gcc verwendete Auswahlprozess ist sinnvoll, wenn wir mit der Tradition beginnen, jeder Klasse, die für ihre Implementierung eine benötigt, eine (einzelne) Quelldatei zuzuweisen. Es wäre schön, die vtable beim Kompilieren dieser Quelldatei auszugeben. Nennen wir das unser Ziel. Der Auswahlprozess muss jedoch funktionieren, auch wenn diese Tradition nicht befolgt wird. Anstatt nach der Implementierung der gesamten Klasse zu suchen, suchen wir nach der Implementierung eines bestimmten Mitglieds der Klasse. Wenn der Tradition gefolgt wird - und wenn dieses Mitglied tatsächlich umgesetzt wird - dann erreicht dies das Ziel.
Das von gcc (und möglicherweise von anderen Compilern) ausgewählte Mitglied ist die erste nicht inline virtuelle Funktion, die nicht rein virtuell ist. Wenn Sie Teil der Menge sind, die Konstruktoren und Destruktoren vor anderen Mitgliedsfunktionen deklariert, hat dieser Destruktor gute Chancen, ausgewählt zu werden. (Sie haben daran gedacht, den Destruktor virtuell zu machen, oder?) Es gibt Ausnahmen. Ich würde erwarten, dass die häufigsten Ausnahmen sind, wenn eine Inline-Definition für den Destruktor bereitgestellt wird und wenn der Standard-Destruktor angefordert wird (mit "
= default
").Der Kluge könnte bemerken, dass eine polymorphe Klasse Inline-Definitionen für alle ihre virtuellen Funktionen bereitstellen darf. Führt das nicht dazu, dass der Auswahlprozess fehlschlägt? Dies ist bei älteren Compilern der Fall. Ich habe gelesen, dass die neuesten Compiler diese Situation angegangen sind, kenne aber keine relevanten Versionsnummern. Ich könnte versuchen, dies nachzuschlagen, aber es ist einfacher, entweder Code zu verwenden oder darauf zu warten, dass sich der Compiler beschwert.
Zusammenfassend gibt es drei Hauptursachen für den Fehler "undefinierter Verweis auf vtable":
Diese Ursachen allein reichen nicht aus, um den Fehler selbst zu verursachen. Diese würden Sie vielmehr ansprechen, um den Fehler zu beheben. Erwarten Sie nicht, dass das absichtliche Erstellen einer dieser Situationen diesen Fehler definitiv hervorruft. Es gibt andere Anforderungen. Erwarten Sie, dass das Beheben dieser Situationen diesen Fehler behebt.
(OK, Nummer 3 könnte ausreichend gewesen sein, als diese Frage gestellt wurde.)
Wie behebe ich den Fehler?
Willkommen zurück, Leute, die vorausspringen! :) :)
= 0
") und deren Definition Sie angeben (nicht "= default
").Beispiel
Die Details der zu erledigenden Aufgaben können variieren und manchmal in separate Fragen verzweigen (z. B. Was ist ein undefinierter Verweis / ungelöster externer Symbolfehler und wie behebe ich ihn? ). Ich werde jedoch ein Beispiel dafür geben, was in einem bestimmten Fall zu tun ist, das neuere Programmierer verwirren könnte.
In Schritt 1 wird erwähnt, dass Ihre Klasse so geändert wird, dass sie eine Funktion eines bestimmten Typs hat. Wenn die Beschreibung dieser Funktion über Ihren Kopf ging, könnten Sie sich in der Situation befinden, die ich ansprechen möchte. Denken Sie daran, dass dies ein Weg ist, um das Ziel zu erreichen. Dies ist nicht der einzige Weg, und es könnte leicht bessere Wege in Ihrer spezifischen Situation geben. Rufen wir Ihre Klasse an
A
. Ist Ihr Destruktor (in Ihrer Klassendefinition) als einer der beiden deklariert?oder
? In diesem Fall ändern zwei Schritte Ihren Destruktor in den gewünschten Funktionstyp. Ändern Sie zuerst diese Zeile in
Fügen Sie zweitens die folgende Zeile in eine Quelldatei ein, die Teil Ihres Projekts ist (vorzugsweise die Datei mit der Klassenimplementierung, falls vorhanden):
Dadurch ist Ihr (virtueller) Destruktor nicht inline und wird nicht vom Compiler generiert. (Sie können jederzeit Änderungen an Ihrem Code-Formatierungsstil vornehmen, z. B. einen Header-Kommentar zur Funktionsdefinition hinzufügen.)
quelle
In verschiedenen Antworten wird viel spekuliert. Ich werde im Folgenden einen ziemlich minimalen Code angeben, der diesen Fehler reproduziert, und erklären, warum er auftritt.
Ziemlich minimaler Code, um diesen Fehler zu reproduzieren
IBase.hpp
Derived.hpp
Derived.cpp
myclass.cpp
Sie können dies mit GCC wie folgt kompilieren:
Sie können den Fehler jetzt reproduzieren, indem Sie ihn
= 0
in IBase.hpp entfernen . Ich erhalte diesen Fehler:Erläuterung
Beachten Sie, dass für den obigen Code keine virtuellen Destruktoren, Konstruktoren oder andere zusätzliche Dateien erforderlich sind, damit die Kompilierung erfolgreich ist (obwohl Sie sie haben sollten).
Um diesen Fehler zu verstehen, gehen Sie wie folgt vor: Linker sucht nach einem Konstruktor für IBase. Dies wird es für den Konstruktor von Derived benötigen. Da Derived jedoch Methoden aus IBase überschreibt, ist eine vtable angehängt, die auf IBase verweist. Wenn der Linker "undefinierter Verweis auf vtable für IBase" sagt, bedeutet dies im Grunde, dass Derived einen vtable-Verweis auf IBase hat, aber keinen kompilierten Objektcode von IBase finden kann, zu dem nachgeschlagen werden kann. Unter dem Strich hat die Klasse IBase Deklarationen ohne Implementierungen. Dies bedeutet, dass eine Methode in IBase als virtuell deklariert ist, wir jedoch vergessen haben, sie als rein virtuell zu markieren ODER ihre Definition anzugeben.
Abschiedstipp
Wenn alles andere fehlschlägt, besteht eine Möglichkeit, diesen Fehler zu beheben, darin, ein minimales Programm zu erstellen, das kompiliert wird, und es dann ständig zu ändern, damit es den gewünschten Status erreicht. Kompilieren Sie zwischendurch weiter, um zu sehen, wann es fehlschlägt.
Hinweis zum ROS- und Catkin-Build-System
Wenn Sie die oben genannten Klassen in ROS mit dem Catkin-Build-System kompiliert haben, benötigen Sie die folgenden Zeilen in CMakeLists.txt:
Die erste Zeile besagt im Grunde, dass wir eine ausführbare Datei mit dem Namen myclass erstellen möchten, und der Code zum Erstellen dieser Dateien enthält die folgenden Dateien. Eine dieser Dateien sollte main () haben. Beachten Sie, dass Sie in CMakeLists.txt keine .hpp-Dateien angeben müssen. Außerdem müssen Sie Derived.cpp nicht als Bibliothek angeben.
quelle
Ich bin gerade auf eine andere Ursache für diesen Fehler gestoßen, auf die Sie prüfen können.
Die Basisklasse definierte eine reine virtuelle Funktion als:
Und die Unterklasse hatte
Das Problem war der Tippfehler, dass der
"=0"
außerhalb der Klammer stehen sollte:Wenn Sie also so weit nach unten scrollen, haben Sie wahrscheinlich keine Antwort gefunden - dies ist etwas anderes, auf das Sie achten müssen.
quelle
Dies kann sehr leicht passieren, wenn Sie vergessen, eine Verknüpfung zu der Objektdatei mit der Definition herzustellen.
quelle
Der GNU C ++ - Compiler muss entscheiden, wo
vtable
die Definition der virtuellen Funktionen eines Objekts abgelegt werden soll, falls Sie die Definition der virtuellen Funktionen eines Objekts auf mehrere Kompilierungseinheiten verteilt haben (z. B. befinden sich einige der Definitionen der virtuellen Funktionen des Objekts in einer CPP-Datei, andere in einer anderen. CPP-Datei usw.).Der Compiler legt die
vtable
Position an der Stelle ab, an der die erste deklarierte virtuelle Funktion definiert ist.Wenn Sie aus irgendeinem Grund vergessen haben, eine Definition für diese erste im Objekt deklarierte virtuelle Funktion anzugeben (oder fälschlicherweise vergessen haben, das kompilierte Objekt in der Verknüpfungsphase hinzuzufügen), wird dieser Fehler angezeigt.
Beachten Sie als Nebeneffekt, dass Sie nur für diese bestimmte virtuelle Funktion nicht den herkömmlichen Linker-Fehler erhalten, da Ihnen die Funktion foo fehlt .
quelle
Nicht um aber zu überqueren. Wenn Sie sich mit Vererbung befassen, war der zweite Google-Treffer das, was ich verpasst hatte, dh. Alle virtuellen Methoden sollten definiert werden.
Sowie:
Weitere Informationen finden Sie unter Answare C ++ Undefined Referenz zu vtable und Vererbung . Ich habe gerade festgestellt, dass es bereits oben erwähnt wurde, aber es könnte jemandem helfen.
quelle
Ok, die Lösung hierfür ist, dass Sie möglicherweise die Definition verpasst haben. Sehen Sie sich das folgende Beispiel an, um den vtable-Compilerfehler zu vermeiden:
quelle
CDasherComponent
es einen Körper für den Destruktor gibt? Es ist definitiv nicht hier - die Frage ist, ob es in der .cc-Datei ist.CDasherModule
sollte der Destruktor explizit definiert werdenvirtual
.CGameModule
als hätte es}
am Ende (nach dem}; // for the class
) ein Extra .CGameModule
mit den Bibliotheken verknüpft, dieCDasherModule
und definierenCDasherComponent
?quelle
Vielleicht trägt das Fehlen des virtuellen Destruktors dazu bei?
quelle
Dies war das erste Suchergebnis für mich, daher dachte ich, ich würde noch etwas hinzufügen, um zu überprüfen: Stellen Sie sicher, dass die Definition der virtuellen Funktionen tatsächlich in der Klasse enthalten ist. In meinem Fall hatte ich Folgendes:
Header-Datei:
und in meiner .cc-Datei:
Dies sollte lesen
quelle
Nicht vielleicht. Auf jeden Fall
~CDasherModule() {}
fehlt.quelle
So viele Antworten hier, aber keine von ihnen schien mein Problem abgedeckt zu haben. Ich hatte folgendes:
Und in einer anderen Datei (natürlich in der Zusammenstellung und Verknüpfung enthalten)
Nun, das hat nicht funktioniert und ich habe den Fehler bekommen, über den alle reden. Um es zu lösen, musste ich die eigentliche Definition von Foo aus der Klassendeklaration als solche entfernen:
Ich bin kein C ++ - Guru, daher kann ich nicht erklären, warum dies korrekter ist, aber es hat das Problem für mich gelöst.
quelle
Also habe ich Qt mit Windows XP und MinGW Compiler verwendet und dieses Ding hat mich verrückt gemacht.
Grundsätzlich wurde die Datei moc_xxx.cpp leer generiert, auch wenn ich hinzugefügt wurde
Q_OBJECT
Das Löschen von Funktionen, die virtuell, explizit und was auch immer Sie vermuten, hat nicht funktioniert. Schließlich fing ich an, Zeile für Zeile zu entfernen, und es stellte sich heraus, dass ich hatte
Um die Datei. Auch wenn das #ifdef wahr war, wurde keine MOC-Datei generiert.
Das Entfernen aller #ifdefs hat das Problem behoben.
Dies geschah nicht mit Windows und VS 2013.
quelle
g++ *.cpp ...
. (Benötigte etwas schnelles und schmutziges, aber qmake war voller Trauer.)Wenn alles andere fehlschlägt, suchen Sie nach Duplikaten. Ich wurde durch den expliziten anfänglichen Verweis auf Konstruktoren und Destruktoren fehlgeleitet, bis ich einen Verweis in einem anderen Beitrag las. Es ist jede ungelöste Methode. In meinem Fall dachte ich, ich hätte die Deklaration, die char * xml als Parameter verwendete, durch eine Deklaration ersetzt, die die unnötig störende const char * xml verwendet, aber stattdessen hatte ich eine neue erstellt und die andere an Ort und Stelle belassen.
quelle
Es gibt viele Möglichkeiten, diesen Fehler zu verursachen, und ich bin sicher, dass viele von ihnen den Fehler verursachen. In meinem Fall gab es aufgrund einer Duplizierung der Quelldatei eine andere Definition derselben Klasse. Diese Datei wurde kompiliert, aber nicht verlinkt, sodass sich der Linker darüber beschwerte, dass er sie nicht finden konnte.
Zusammenfassend würde ich sagen, wenn Sie die Klasse lange genug angestarrt haben und nicht sehen können, welches mögliche Syntaxproblem sie verursachen könnte, suchen Sie nach Build-Problemen wie einer fehlenden oder einer duplizierten Datei.
quelle
In meinem Fall verwende ich Qt und habe eine
QObject
Unterklasse in einerfoo.cpp
(nicht.h
) Datei definiert. Das Update sollte#include "foo.moc"
am Ende von hinzugefügt werdenfoo.cpp
.quelle
Ich denke, es ist auch erwähnenswert, dass Sie die Nachricht auch erhalten, wenn Sie versuchen, eine Verknüpfung zu einem Objekt einer Klasse herzustellen , die mindestens eine virtuelle Methode hat und der Linker die Datei nicht finden kann. Zum Beispiel:
Foo.hpp:
Foo.cpp:
Zusammengestellt mit:
Und main.cpp:
Zusammengestellt und verknüpft mit:
Gibt unseren Lieblingsfehler:
Dies ist auf mein Verständnis zurückzuführen, weil:
Vtable wird pro Klasse zur Kompilierungszeit erstellt
Linker hat keinen Zugriff auf vtable in Foo.o.
quelle
Ich habe diesen Fehler im folgenden Szenario erhalten
Stellen Sie sich einen Fall vor, in dem Sie die Implementierung von Elementfunktionen einer Klasse in der Header-Datei selbst definiert haben. Diese Header-Datei ist ein exportierter Header (mit anderen Worten, sie wird möglicherweise in eine allgemeine Datei kopiert / direkt in Ihre Codebasis aufgenommen). Jetzt haben Sie beschlossen, die Implementierung der Mitgliedsfunktionen in eine CPP-Datei zu trennen. Nachdem Sie die Implementierung in .cpp getrennt / verschoben haben, enthält die Header-Datei nur noch die Prototypen der Elementfunktionen innerhalb der Klasse. Wenn Sie nach den obigen Änderungen Ihre Codebasis erstellen, wird möglicherweise der Fehler "undefinierter Verweis auf 'vtable ..." angezeigt.
Um dies zu beheben, stellen Sie vor dem Erstellen sicher, dass Sie die Header-Datei (an der Sie Änderungen vorgenommen haben) im Verzeichnis common / include löschen. Stellen Sie außerdem sicher, dass Sie Ihr Makefile ändern, um die neue .o-Datei aufzunehmen / hinzuzufügen, die aus der neuen .cpp-Datei erstellt wurde, die Sie gerade erstellt haben. Wenn Sie diese Schritte ausführen, beschwert sich der Compiler / Linker nicht mehr.
quelle
Ich habe diese Art von Fehler in Situationen erhalten, in denen ich versucht habe, eine Verknüpfung zu einem Objekt herzustellen, als ich einen Make-Fehler bekam, der das Hinzufügen des Objekts zum Archiv verhinderte.
Angenommen, ich habe libXYZ.a, das bioseq.o in int haben soll, aber nicht.
Ich habe eine Fehlermeldung erhalten:
Dies unterscheidet sich von allen oben genannten. Ich würde dieses fehlende Objekt im Archivproblem nennen.
quelle
Es ist auch möglich, dass Sie eine Nachricht wie erhalten
Wenn Sie vergessen haben, eine virtuelle Funktion einer Klasse FakeClass1 zu definieren, wenn Sie versuchen, einen Komponententest für eine andere Klasse SomeClass zu verknüpfen.
Und
In diesem Fall schlage ich vor, dass Sie Ihre Fälschung für Klasse 1 noch einmal überprüfen. Sie werden wahrscheinlich feststellen, dass Sie möglicherweise vergessen haben, eine virtuelle Funktion
ForgottenFunc
in Ihrer gefälschten Klasse zu definieren .quelle
Ich habe diesen Fehler erhalten, als ich einem vorhandenen Quell / Header-Paar eine zweite Klasse hinzugefügt habe. Zwei Klassenheader in derselben .h-Datei und Funktionsdefinitionen für zwei Klassen in derselben .cpp-Datei.
Ich habe das schon einmal erfolgreich gemacht, mit Klassen, die eng zusammenarbeiten sollen, aber anscheinend hat mich diesmal etwas nicht gemocht. Ich weiß immer noch nicht was, aber die Aufteilung in eine Klasse pro Kompilierungseinheit hat das Problem behoben.
Der fehlgeschlagene Versuch:
_gui_icondata.h:
_gui_icondata.cpp:
Wiederum fügte das Hinzufügen eines neuen Quell / Header-Paares und das wörtliche Ausschneiden / Einfügen der IconWithData-Klasse "gerade funktioniert" hinzu.
quelle
Mein Fall war albern, ich hatte versehentlich ein Extra
"
danach#include
und weißt du was?Ich habe mich stundenlang am Kopf und am Gesicht gekratzt und virtuelle Funktionen kommentiert, um zu sehen, ob sich etwas geändert hat, und schließlich wurde durch Entfernen des Extra
"
alles repariert! Diese Art von Dingen muss wirklich zu einem Kompilierungsfehler führen, nicht zu einem Linkfehler.Mit extra
"
meine ich:quelle
In meinem Fall hatte ich eine Basisklasse namens Person und zwei abgeleitete Klassen namens Student und Professor.
Wie mein Programm repariert wurde, war: 1. Ich habe alle Funktionen in der Basisklasse gemacht.
Pure Virtual.
2. Ich habe alle virtuellen Destruktoren als verwendetdefault ones.
quelle
Ich habe diesen Fehler nur erhalten, weil sich der Name eines Konstruktorarguments in der Header-Datei und in der Implementierungsdatei unterschied. Die Konstruktorsignatur lautet
und was ich in der Implementierung geschrieben habe, begann mit
daher habe ich versehentlich "pset" durch "pest" ersetzt. Der Compiler beschwerte sich über diesen einen und zwei andere Konstruktoren, bei denen überhaupt kein Fehler auftrat. Ich verwende g ++ Version 4.9.1 unter Ubuntu. Das Definieren eines virtuellen Destruktors in dieser abgeleiteten Klasse machte keinen Unterschied (es wird in der Basisklasse definiert). Ich hätte diesen Fehler nie gefunden, wenn ich die Körper der Konstruktoren nicht in die Header-Datei eingefügt und sie so in der Klasse definiert hätte.
quelle