Référence non définie à vtable
Si, je suis l'infâme horrible
Erreurréférence non définie à " vtable...
pour le code suivant (la classe en question Est CGameModule.) et je ne peux pas pour la vie de me comprendre quel est le problème. Au début, je pensais que c'était lié à l'oubli de donner une fonction virtuelle d'un corps, mais comme je le comprends, tout est ici. La chaîne de l'héritage est un peu longue, mais voici le code source. Je ne sais pas quelle autre information je dois fournir.
Note: le constructeur est l'endroit où cette erreur se produit, il semblerait.
mon 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;
};
hérite de...
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;
};
qui hérite de....
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
27 réponses
le GCC FAQ a une entrée sur elle:
La solution est de s'assurer que toutes les méthodes virtuelles qui ne sont pas pures sont définis. Notez qu'un destructeur doit être définie, même si elle est déclarée pure virtuel [classe.dtor] / 7.
pour ce que ça vaut, oublier un corps sur un destructeur virtuel génère ce qui suit:
référence non définie à "vtable for CYourClass".
j'ajoute une note parce que le message d'erreur est trompeur. (C'était avec la version 4.6.3 de gcc.)
Donc, j'ai compris le problème et c'était une combinaison de mauvaise logique, et n'étant pas familiarisé avec la automake/autotools monde. J'ajoutais les bons fichiers à mon Makefile.am template, mais je n'étais pas sûr quelle étape dans notre processus de construction a réellement créé le makefile lui-même. Donc, je compilais avec un vieux makefile qui n'avait aucune idée de mes nouveaux fichiers.
Merci pour les réponses et le lien vers la FAQ GCC. Je ne manquerai pas de lire que pour évitez ce problème pour une raison réelle.
si vous utilisez Qt, essayez qmake. Si cette erreur est dans la classe du widget, qmake n'a peut-être pas remarqué que la classe de l'ui vtable devrait être régénérée. Cela a réglé le problème pour moi.
j'ai simplement eu cette erreur parce que mon fichier cpp n'était pas dans le makefile.
une référence non définie à vtable peut se produire en raison de la situation suivante également. Essayez juste ceci:
Classe A Contient:
virtual void functionA(parameters)=0;
virtual void functionB(parameters);
La Classe B Contient:"
- la définition des fonctions ci-dessus.
- la définition de la fonction ci-dessusb.
Classe C Contient: Maintenant, vous écrivez une Classe C dans lequel vous allez dériver de la Classe A.
maintenant si vous essayez de compiler vous obtiendrez la référence non définie à vtable pour la Classe C comme erreur.
raison:
functionA
est défini comme étant purement virtuel et sa définition est donnée dans la classe B.
functionB
est défini comme virtuel (pas purement virtuel) de sorte qu'il tente de trouver sa définition dans la Classe A elle-même, mais vous avez fourni sa définition dans la classe B.
Solution:
- Faire fonction B comme pure virtuelle (si vous avez exigence comme cela)
virtual void functionB(parameters) =0;
(Cela fonctionne il est Testé) - Définition pour functionB en Classe elle-même, gardant comme virtuel . (J'espère que ça fonctionne comme je n'ai pas essayer)
je viens de rencontrer une autre cause pour cette erreur que vous pouvez vérifier.
la classe de base définit une fonction virtuelle pure comme suit:
virtual int foo(int x = 0);
et la sous-classe avait
int foo(int x) override;
le problème était la faute de frappe que le "=0"
était censé être en dehors de la parenthèse:
virtual int foo(int x) = 0;
donc, au cas où vous vous déplaciez si bas, vous n'avez probablement pas trouvé la réponse - c'est bien autre chose à vérifier.
le compilateur GNU C++ doit prendre une décision où placer le vtable
dans le cas où vous avez la définition des fonctions virtuelles d'un objet réparties sur plusieurs unités de compilation (par exemple, certaines des définitions de fonctions virtuelles des objets se trouvent dans A.cpp produire d'autres dans une autre .fichier cpp, et ainsi de suite).
le compilateur choisit de mettre le vtable
au même endroit que celui où la première fonction virtuelle déclarée est définie.
maintenant si vous avez oublié de donner une définition de cette première fonction virtuelle déclaré dans l'objet (ou à tort oublié d'ajouter l'objet compilé le lien entre la phase de), vous obtiendrez cette erreur.
comme un effet secondaire, s'il vous plaît noter que seulement pour cette fonction virtuelle particulière, vous ne recevrez pas l'erreur de linker traditionnel comme vous êtes fonction manquante foo .
cela peut se produire assez facilement si vous oubliez de lier au fichier objet qui a la définition.
c'est une erreur terrible parce qu'il semble que les gens ont supposé peu de choses arbitraires comme cause de cette erreur. Par exemple, quelqu'un a dit que vous devez avoir un destructeur virtuel non-pur en base alors que d'autres personnes ont spéculé que ce destructeur doit être dans son propre fichier cpp et encore un autre a dit que l'ordre des fichiers include a causé l'erreur! Ces causes ne semblent pas être vraies.
Si tout le reste échoue, alors une façon de déboguer cette erreur est de construire programme minimal qui compile et puis continue de le changer pour qu'il arrive à l'état que vous voulez. Entre - temps, continuez de compiler pour voir quand il commence à échouer.
permettez-moi donc de présenter un programme complet qui compile fine, utilise des interfaces de style C++ et a ses propres fichiers cpp et en-tête:
IBase.hpp
#pragma once
class IBase {
public:
virtual void action() = 0;
};
Derived.hpp
#pragma once
#include "IBase.hpp"
class Derived : public IBase {
public:
Derived(int a);
void action() override;
};
Derived.cpp
#include "Derived.hpp"
Derived::Derived(int a) { }
void Derived::action() {}
maclasse.cpp
#include <memory>
#include "Derived.hpp"
class MyClass {
public:
MyClass(std::shared_ptr<Derived> newInstance) : instance(newInstance) {
}
void doSomething() {
instance->action();
}
private:
std::shared_ptr<Derived> instance;
};
int main(int argc, char** argv) {
Derived myInstance(5);
MyClass c(std::make_shared<Derived>(myInstance));
c.doSomething();
return 0;
}
vous pouvez compiler ceci en utilisant GCC comme ceci:
g++ -std=c++11 -o a.out myclass.cpp Derived.cpp
notez que cela ne nécessite pas de destructeurs virtuels, de constructeurs ou d'autres fichiers supplémentaires pour que la compilation soit réussie (bien que vous devriez les avoir). Vous pouvez maintenant reproduire l'erreur en supprimant = 0
dans IBase.hpp. Je comprends cette erreur:
~/.../catkin_ws$ g++ -std=c++11 -o /tmp/m.out /tmp/myclass.cpp /tmp/Derived.cpp
/tmp/cclLscB9.o: In function `IBase::IBase(IBase const&)':
myclass.cpp:(.text._ZN5IBaseC2ERKS_[_ZN5IBaseC5ERKS_]+0x13): undefined reference to `vtable for IBase'
/tmp/cc8Smvhm.o: In function `IBase::IBase()':
Derived.cpp:(.text._ZN5IBaseC2Ev[_ZN5IBaseC5Ev]+0xf): undefined reference to `vtable for IBase'
/tmp/cc8Smvhm.o:(.rodata._ZTI7Derived[_ZTI7Derived]+0x10): undefined reference to `typeinfo for IBase'
collect2: error: ld returned 1 exit status
La façon de comprendre cette erreur est la suivante: Linker cherche le constructeur D'IBase. Il en aura besoin pour le constructeur de Derived. Cependant, comme les méthodes dérivées overrides D'IBase, il a vtable attaché à elle qui fera référence à IBase. Quand linker dit "référence non définie à vtable for IBase" cela signifie essentiellement que Derived a vtable référence à IBase mais il ne peut pas trouver n'importe quel code objet compilé D'IBase à regarder. De sorte que le bas de ligne est-ce que la classe IBase a des déclarations sans implémentation. Cela signifie qu'une méthode dans IBase est déclarée comme virtuelle, mais nous avons oublié de la marquer comme purement virtuelle ou de fournir sa définition.
Note sur le système de construction ROS et Catkin
si vous compiliez l'ensemble de classes ci-dessus dans ROS en utilisant catkin build system, alors vous aurez besoin des lignes suivantes dans CMakeLists.txt:
add_executable(myclass src/myclass.cpp src/Derived.cpp)
add_dependencies(myclass theseus_myclass_cpp)
target_link_libraries(myclass ${catkin_LIBRARIES})
la première ligne essentiellement dit que nous voulons faire un exécutable nommé myclass et le code pour le construire peut être trouvé des fichiers qui suivent. Un de ces fichiers devrait avoir main(). Notez que vous n'avez pas à spécifier .des fichiers HPP n'importe où dans les listes Cmakel.txt. Aussi, vous ne devez pas spécifier dérivé.rpc, de la bibliothèque.
ne pas croiser les poteaux mais. Si vous avez affaire à héritage le deuxième google hit était ce que j'avais manqué, c'est-à-dire. toutes les méthodes virtuelles doivent être définis.
tels que:
virtual void fooBar() = 0;
Voir answare C++ Undefined Reference to vtable et de l'héritage pour plus de détails. Je viens de réaliser que c'est déjà mentionné ci-dessus, mais ça pourrait aider quelqu'un.
Ok, la solution est que vous avez manqué sur la définition. Voir l'exemple ci-dessous pour éviter l'erreur du compilateur vtable:
// In the CGameModule.h
class CGameModule
{
public:
CGameModule();
~CGameModule();
virtual void init();
};
// In the CGameModule.cpp
#include "CGameModule.h"
CGameModule::CGameModule()
{
}
CGameModule::~CGameModule()
{
}
void CGameModule::init() // Add the definition
{
}
- Êtes-vous sûr que
CDasherComponent
a un corps pour le destructeur? Il est certainement pas ici - la question est si elle est dans le .fichier cc. - du point de vue du style,
CDasherModule
devrait définir explicitement son destructeurvirtual
. - il ressemble à
CGameModule
a un extra}
à la fin (après le}; // for the class
). - est
CGameModule
étant lié aux bibliothèques qui définissentCDasherModule
etCDasherComponent
?
peut-être que manquer le destructeur virtuel est un facteur contributif?
virtual ~CDasherModule(){};
C'était le premier résultat de recherche pour moi donc, j'ai pensé ajouter une autre chose à vérifier: assurez-vous que la définition de fonctions virtuelles sont réellement à la classe. Dans mon cas, j'avais ceci:
fichier D'en-tête:
class A {
public:
virtual void foo() = 0;
};
class B : public A {
public:
void foo() override;
};
et dans mon .cc file:
void foo() {
...
}
lire
void B::foo() {
}
peut-être pas. Définitivement ~CDasherModule() {}
est manquant.
tant de réponses ici mais aucune ne semblait avoir couvert ce que mon problème était. J'ai eu le suivant:
class I {
virtual void Foo()=0;
};
et dans un autre fichier (inclus dans la compilation et le lien, bien sûr)
class C : public I{
void Foo() {
//bar
}
};
ça n'a pas marché et j'ai eu l'erreur dont tout le monde parle. Pour le résoudre, j'ai dû déplacer la définition actuelle de Foo hors de la déclaration de classe comme telle:
class C : public I{
void Foo();
};
C::Foo(){
//bar
}
Je ne suis pas un gourou C++ donc je ne peux pas expliquer pourquoi c'est plus correct mais ça a résolu le problème pour moi.
donc J'utilisais Qt avec Windows XP et MinGW compiler et cette chose me rendait fou.
essentiellement le moc_xxx.cpp a été généré vide même lorsque j'ai été ajouté
Q_OBJECT
supprimer tout ce qui rend les fonctions virtuelles, explicites et tout ce que vous devinez ne fonctionne pas. Finalement j'ai commencé à enlever ligne par ligne et il s'est avéré que j'avais
#ifdef something
autour du fichier. Même lorsque l' #ifdef was true le fichier moc n'a pas été généré.
donc supprimer tous les #ifdefs a résolu le problème.
cette chose ne se passait pas avec Windows et VS 2013.
j'ai eu cette erreur dans le scénario suivant
prenons le cas où vous avez défini la mise en œuvre des fonctions membres d'une classe dans le fichier d'en-tête lui-même. Ce fichier d'en-tête est un en-tête exporté (en d'autres termes, il peut être copié dans un fichier common/include directement dans votre base de codes). Maintenant que vous avez décidé de séparer la mise en œuvre des fonctions de membre de .fichier cpp. Après avoir séparé / déplacé l'implémentation .rpc, le fichier d'en-tête a maintenant juste les prototypes des fonctions de membre à l'intérieur de la classe. Après les modifications ci-dessus, si vous construisez votre codebase vous pouvez obtenir la "référence non définie à 'vtable..." erreur.
pour corriger cela, avant de construire, assurez-vous de supprimer le fichier d'en-tête (auquel vous avez apporté des modifications) dans common/include directory. Assurez-vous également que vous changez votre makefile pour accommodate/add the new .o fichier construit à partir du nouveau .rpc fichier que vous venez de créer. Quand vous faites ces étapes le compilateur / linker n'auront plus à se plaindre.
si tout le reste échoue, cherchez la duplication. J'ai été mal dirigé par la référence initiale explicite aux constructeurs et destructeurs jusqu'à ce que je lise une référence dans un autre post. C'est n'importe quelle" méthode 151920920 " non résolue. Dans mon cas, je pensais avoir remplacé la déclaration qui utilisait char *xml comme paramètre par une déclaration utilisant le xml inutilement gênant de const char*, mais au lieu de cela, j'en avais créé une nouvelle et laissé l'autre en place.
il y a beaucoup de possibilités mentionnées pour causer cette erreur, et je suis sûr que beaucoup d'entre elles causent l'erreur. Dans mon cas, il y avait une autre définition de la même classe, en raison d'une duplication du fichier source. Ce fichier a été compilé, mais pas lié, de sorte que le linker se plaignait d'être incapable de le trouver.
pour résumer, je dirais que si vous avez regardé la classe assez longtemps et ne pouvez pas voir quelle syntaxe possible le problème pourrait en être la cause, cherchez les problèmes de construction comme un fichier manquant ou un fichier dupliqué.
j'ai eu ce type d'erreur dans des situations où j'essayais de faire un lien vers un objet quand j'ai eu un bug de make qui a empêché l'objet d'être ajouté à l'archive.
dis que j'ai libXYZ.un qui est supposé avoir un bioseq.o in int mais ce n'est pas le cas.
j'ai eu une erreur:
combineseq.cpp:(.text+0xabc): undefined reference to `vtable for bioseq'
Ce est très différente de tout ce qui précède. J'appellerais cet objet manquant dans le problème des archives.
dans mon cas, J'utilise Qt et j'avais défini une sous-classe QObject
dans un fichier foo.cpp
(pas .h
). La solution était d'ajouter #include "foo.moc"
à la fin de foo.cpp
.
il est aussi possible que vous receviez un message comme
SomeClassToTest.host.o: In function `class1::class1(std::string const&)':
class1.hpp:114: undefined reference to `vtable for class1'
SomeClassToTest.host.o: In function `class1::~class1()':
class1.hpp:119: undefined reference to `vtable for class1'
collect2: error: ld returned 1 exit status
[link] FAILED: 'g++' '-o' 'stage/tests/SomeClassToTest' 'object/tests/SomeClassToTest.host.o' 'object/tests/FakeClass1.SomeClassToTest.host.o'
si vous oubliez de définir une fonction virtuelle d'une classe FakeClass1 lorsque vous essayez de lier un test unitaire pour une autre classe SomeClass.
//class declaration in class1.h
class class1
{
public:
class1()
{
}
virtual ~class1()
{
}
virtual void ForgottenFunc();
};
et
//class definition in FakeClass1.h
//...
//void ForgottenFunc() {} is missing here
dans ce cas, je vous suggère de vérifier votre faux pour la classe 1 Une fois de plus. Vous trouverez probablement que vous avez oublié de définir une fonction virtuelle ForgottenFunc
dans votre faux de la classe.
j'ai eu cette erreur quand j'ai ajouté une seconde classe à une paire source/en-tête existante. Deux têtes de classe dans le même .h de fichier, et les définitions de fonction pour deux classes dans le même .fichier cpp.
Je l'ai déjà fait avec succès, avec des classes qui sont destinées à travailler étroitement ensemble, mais apparemment quelque chose ne m'a pas aimé cette fois. Je ne sais toujours pas quoi, mais en les divisant en une classe par unité de compilation, ça s'est arrangé.
l'échec de La tentative:
_gui_icondata.h:
#ifndef ICONDATA_H
#define ICONDATA_H
class Data;
class QPixmap;
class IconData
{
public:
explicit IconData();
virtual ~IconData();
virtual void setData(Data* newData);
Data* getData() const;
virtual const QPixmap* getPixmap() const = 0;
void toggleSelected();
void toggleMirror();
virtual void updateSelection() = 0;
virtual void updatePixmap(const QPixmap* pixmap) = 0;
protected:
Data* myData;
};
//--------------------------------------------------------------------------------------------------
#include "_gui_icon.h"
class IconWithData : public Icon, public IconData
{
Q_OBJECT
public:
explicit IconWithData(QWidget* parent);
virtual ~IconWithData();
virtual const QPixmap* getPixmap() const;
virtual void updateSelection();
virtual void updatePixmap(const QPixmap* pixmap);
signals:
public slots:
};
#endif // ICONDATA_H
_gui_icondata.cpp:
#include "_gui_icondata.h"
#include "data.h"
IconData::IconData()
{
myData = 0;
}
IconData::~IconData()
{
if(myData)
{
myData->removeIcon(this);
}
//don't need to clean up any more; this entire object is going away anyway
}
void IconData::setData(Data* newData)
{
if(myData)
{
myData->removeIcon(this);
}
myData = newData;
if(myData)
{
myData->addIcon(this, false);
}
updateSelection();
}
Data* IconData::getData() const
{
return myData;
}
void IconData::toggleSelected()
{
if(!myData)
{
return;
}
myData->setSelected(!myData->getSelected());
updateSelection();
}
void IconData::toggleMirror()
{
if(!myData)
{
return;
}
myData->setMirrored(!myData->getMirrored());
updateSelection();
}
//--------------------------------------------------------------------------------------------------
IconWithData::IconWithData(QWidget* parent) :
Icon(parent), IconData()
{
}
IconWithData::~IconWithData()
{
}
const QPixmap* IconWithData::getPixmap() const
{
return Icon::pixmap();
}
void IconWithData::updateSelection()
{
}
void IconWithData::updatePixmap(const QPixmap* pixmap)
{
Icon::setPixmap(pixmap, true, true);
}
encore une fois, en ajoutant une nouvelle paire source/en-tête et en coupant/collant la classe IconWithData mot à mot dans "just worked".
je pense qu'il est également intéressant de mentionner que vous obtiendrez également le message lorsque vous essayez de lier à l'objet de n'importe quelle classe qui a au moins une méthode virtuelle et linker ne peut pas trouver le fichier. Par exemple:
Foo.hpp:
class Foo
{
public:
virtual void StartFooing();
};
Foo.cpp:
#include "Foo.hpp"
void Foo::StartFooing(){ //fooing }
compilé avec:
g++ Foo.cpp -c
et main.rpc:
#include "Foo.hpp"
int main()
{
Foo foo;
}
compilé et lié avec:
g++ main.cpp -o main
donne notre erreur préférée:
/tmp/cclKnW0g.o: Dans la fonction
main': main.cpp:(.text+0x1a): undefined reference to
vtable pour Foo' collect2: erreur: ld a retourné 1 sortie le statut de
cela provient de mon undestanding becasue:
-
Vtable est créé par la classe au moment de la compilation
-
de l'éditeur de liens n'a pas accès à vtable qui est dans Foo.o
j'ai eu cette erreur juste parce que le nom d'un argument constructeur différait dans le fichier d'en-tête et dans le fichier d'implémentation. La signature du constructeur est
PointSet (const PointSet & pset, Parent * parent = 0);
et ce que j'ai écrit dans l'implémentation a commencé avec
PointSet (const PointSet & pest, Parent * parent)
j'ai donc accidentellement remplacé" pset "par"pest". Le compilateur se plaignait de celui-ci et de deux autres constructeurs dans lesquels il n'y avait aucune erreur. J'utilise la version 4.9.1 de g++ sous Ubuntu. Et définir un destructeur virtuel dans cette classe dérivée n'a fait aucune différence (il est défini dans la classe de base). Je n'aurais jamais trouvé ce bug si je n'avais pas collé les corps des constructeurs dans le fichier d'en-tête, les définissant ainsi en classe.