Atunci când construirea meu program C++, am'm obtinerea mesaj de eroare
nedefinit de referință pentru 'vtable...
Care este cauza acestei probleme? Cum pot repara asta?
Așa se întâmplă că am'm obtinerea de eroare pentru codul de mai jos (clasa în cauză este CGameModule.) și nu pot să-mi înțeleg care este problema. La început, am crezut că a fost legat de a uita pentru a da un virtual funcție de un corp, dar, din câte am înțeles, totul este aici. Moștenirea lanț este un pic cam lung, dar aici este legate de codul sursă. Am'm nu sunt sigur ce alte informații ar trebui să ofere.
Notă: constructorul este în cazul în care această eroare se întâmplă, l'd par.
Codul meu:
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;
};
Moștenește de la...
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;
};
Care moștenește de la....
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
De GCC FAQ are o intrare pe ea:
soluția este să se asigure că toate metodele virtuale care nu sunt pure sunt definite. Rețineți că un destructor trebuie să fie definite, chiar dacă acesta este declarat pur-virtual [clasa.dtor]/7.
Pentru ceea ce merită, uitând un corp pe un destructor virtual generează următoarele:
nedefinit referire la `vtable pentru CYourClass'.
Eu sunt adăugarea o notă deoarece mesajul de eroare este înșelătoare. (Acest lucru a fost cu gcc versiune 4.6.3.)
Deci, am'am dat seama de problema si a fost o combinație de logica rău și nu sunt complet familiarizați cu automake/autotools lume. Am fost adăugarea de fișierele corecte a mea Makefile.sunt model, dar nu't de sigur care pas în procesul de construire a creat de fapt makefile în sine. Deci, am fost compilarea cu un vechi makefile care nu a avut nici o idee despre noua mea fișiere de orice fel.
Multumesc pentru raspunsuri si link-ul de la CCG FAQ. Eu voi fi sigur de a citi că, pentru a evita această problemă, care apar pentru un motiv real.
Dacă sunteți folosind Qt, încercați revedea qmake. Dacă această eroare este în widget's class, qmake-ar putea să nu observați că ui clasa vtable ar trebui să fie regenerat. Această rezolvat problema pentru mine.
Nedefinit de referință pentru vtable pot să apară datorită următoarelor situație, de asemenea,. Doar să încercați acest lucru:
Clasa A Conține:
virtual void functionA(parameters)=0;
virtual void functionB(parameters);
Clasa B Contine:
Clasa C Conține: Acum're scris o Clasă C în care aveți de gând pentru a obține de la Clasa A.
Acum, dacă încercați să compilați veți obține Nedefinit de referință pentru vtable pentru Clasa C ca eroare.
Motiv:
functionA
este definit ca pur virtuale și definiția acestuia este prevăzută în Clasa B.
functionB
este definit ca virtual (NU VIRTUALE PURE) așa că încearcă să-și găsească o definiție în Clasă în sine, dar cu condiția de definiție în Clasa B.
Soluție:
virtual void functionB(parametri) =0;
(Aceasta funcționează este Testat)Există o mulțime de speculații întâmplă în diverse răspunsuri aici. Am'll de mai jos da o destul de minime cod care reproduce această eroare și să explice de ce apare.
Destul de Minime Cod pentru a Reproduce Această Eroare
IBase.che
#pragma once
class IBase {
public:
virtual void action() = 0;
};
Derivate.che
#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() {}
myclass.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;
}
Puteți compila acest lucru, folosind GCC astfel:
g++ -std=c++11 -o a.out myclass.cpp Derived.cpp
Acum puteți reproduce eroarea prin eliminarea = 0
în IBase.che. Primesc aceasta eroare:
~/.../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
Explicație
Observați că codul de mai sus nu are nevoie de nici virtual destructori, constructori sau orice alte fișiere suplimentare pentru a compila pentru a fi de succes (deși ar trebui să le aibă).
Cum să înțelegem această eroare este după cum urmează: Linker-ul este în căutarea pentru constructorul de IBase. Acest lucru va avea nevoie de ea pentru constructorul de Derivate. Cu toate acestea, ca Derivat suprascrie metode de IBase, a vtable atașat la acesta, care va referire IBase. Când linker spune "nedefinit de referință pentru vtable pentru IBase" aceasta înseamnă de fapt că Derivat a vtable referire la IBase dar poate't găsi orice obiect compilate codul de IBase să se uite în sus la. Deci, linia de jos este că clasa IBase a declarațiilor fără implementări. Acest lucru înseamnă o metodă în IBase este declarată virtuală, dar am uitat să-l marcați ca pur virtual SAU oferă definiția sa.
Despărțire Sfat
Dacă toate altceva nu reușește, atunci o modalitate de a depana această eroare este de a construi minim program care nu a compila și apoi să păstreze o schimba pentru ca se ajunge la starea pe care doriți. În între, ține strâns să vadă când începe să eșueze.
Notă pe ROS și Catkin construi sistemul
Dacă ai fost compilarea de mai sus set de clase în ROS folosind catkin construi sistemul atunci veți avea nevoie de următoarele linii în CMakeLists.txt:
add_executable(myclass src/myclass.cpp src/Derived.cpp)
add_dependencies(myclass theseus_myclass_cpp)
target_link_libraries(myclass ${catkin_LIBRARIES})
Prima linie de fapt spune că vrem să facem un executabil numit myclass și codul pentru a construi acest lucru poate fi găsit fișierele care urmează. Unul dintre aceste fișiere ar trebui să aibă main(). Observați că nu't trebuie să specificați .che fișiere de oriunde în CMakeLists.txt. De asemenea, don't trebuie să specificați Derived.cpp ca bibliotecă.
Am fugit într-o altă cauză pentru această eroare pe care le puteți verifica pentru.
Clasa de bază a definit o pur virtuale funcția ca:
virtual int foo(int x = 0);
Și subclasa a
int foo(int x) override;
Problema a fost typo că `"=0" a fost trebuia să fie în afara parantezelor:
virtual int foo(int x) = 0;
Deci, în cazul în care te're defilare de departe în jos, tu, probabil, nu't găsi răspunsul - acest lucru este ceva pentru a verifica.
GNU C++ compiler trebuie să ia o decizie în cazul în care pentru a pune vtable
în cazul în care aveți definirea de funcții virtuale a unui obiect repartizate pe mai multe compilatii de unități (de exemplu, unele dintre obiecte virtuale funcții definiții sunt într-o .fișier cpp alții în alta .fișier cpp, și așa mai departe).
Compilatorul alege pentru a pune `vtable în același loc ca și în cazul în care primul a declarat virtuale funcția este definită.
Acum, dacă vă pentru un motiv oarecare a uitat să ofere o definiție pentru prima virtual funcția declarat în obiect (sau din greșeală, a uitat să adauge obiect compilate la conectarea fazei), veți obține această eroare.
Ca un efect secundar, vă rugăm să rețineți că numai pentru acest special funcția virtuale ai câștigat't obține tradiționale linker error ca lipsesc funcția de foo.
Să nu treacă post dar. Dacă ai de-a face cu moștenire cel de-al doilea google lovit a fost ceea ce am avut de pierdut, de exemplu. toate metodele virtuale ar trebui să fie definite.
Cum ar fi:
virtual void fooBar() = 0;
Vezi answare https://stackoverflow.com/q/9406580/1592572 pentru detalii. Doar a dat seama's-a menționat deja mai sus, dar ce naiba te-ar putea ajuta cineva.
Ok, soluția la această este că ți-ai ratat pe definiție. A se vedea exemplul de mai jos, pentru a evita vtable compiler eroare:
// 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
{
}
CDasherModule
ar trebui să își definească în mod explicit destructor "virtuale".CGameModule
are o }
la sfârșit (după }; // pentru clasa
).fiind legate de bibliotecile care definesc
CDasherModule " și " CDasherComponent`?Acesta a fost primul rezultat de căutare pentru mine, așa că am crezut că am'd a adăuga un alt lucru pentru a verifica: asigurați-vă că definirea de funcții virtuale sunt de fapt pe clasa. În cazul meu, am avut asa:
Fișier antet:
class A {
public:
virtual void foo() = 0;
};
class B : public A {
public:
void foo() override;
};
și în a mea .cc fișier:
void foo() {
...
}
Acest lucru ar trebui să citiți
void B::foo() {
}
vtable
? vtable
generat? Un vtable este generat automat (uneori numit "emise"), de către compilator. Un compilator ar putea emite o vtable în fiecare unitate de traducere, care vede o polimorfă clasa definiție, dar care ar fi, de obicei, inutile nejustificată. O alternativă (utilizate de către ccg, și probabil și de alții) este de a alege o singură unitate de traducere în care la locul vtable, similar cu modul în care ar alege un singur fișier sursă în care pentru a pune o clasa' date statice de membri. Dacă acest proces de selecție nu reușește să alege orice traducere de unități, apoi vtable devine un nedefinit de referință. Prin urmare, eroarea, al cărui mesaj este, desigur, deosebit de clar. În mod similar, dacă procesul de selecție se alege o unitate de traducere, dar, ca obiect de fișier nu este prevăzută de linker-ul, apoi vtable devine un nedefinit de referință. Din păcate, mesajul de eroare poate fi chiar mai puțin clară în acest caz decât în cazul în care procesul de selecție nu a reușit. (Datorită respondenti care au menționat această posibilitate. Probabil că m-aș fi uitat în caz contrar.) Procesul de selecție utilizate de către ccg are sens dacă vom începe cu tradiția dedică un (singur) fișier sursă pentru fiecare clasă care are nevoie de una pentru punerea sa în aplicare. Ar fi frumos să emit vtable atunci când compilarea faptul că fișierul sursă. Las's de apel că scopul nostru. Cu toate acestea, procesul de selecție trebuie să lucreze, chiar dacă această tradiție nu este urmat. Deci, în loc de a privi pentru punerea în aplicare a întregii clase, las's uite pentru punerea în aplicare a unui anumit membru al clasei. Dacă tradiția este urmat – și în cazul în care membrul este de fapt implementat – apoi aceasta atinge scopul. Statele selectate de către ccg (și, potențial, de alte compilatoare) este primul non-inline virtual funcție care nu este pur virtual. Dacă faci parte dintre cei care declară constructori și destructori înainte de alte funcții membre, atunci destructorul are o bună șansă de a fi selectate. (Vă amintiți de a face destructor virtual, nu?) Există și excepții; I'd așteptăm ca cele mai frecvente exceptii sunt atunci când o linie definiție este prevăzută pentru destructor și atunci când default destructor este solicitat (folosind "`= default"). Perspicace ar putea observa că un polimorfism clasa este permis pentru a oferi inline definiții pentru toate funcții virtuale. Nu't care determina procesul de selecție pentru a reuși? În vârstă de compilatoare. Am'am citit că cele mai recente compilatoare au abordat această situație, dar nu știu relevante numere de versiune. Am putea încerca să arăți asta, dar's ușor să fie codul în jurul valorii de ea sau să așteptați pentru compilatorul să se plângă. În rezumat, există trei cauze ale "nedefinit de referință pentru vtable" eroare:
Bine ați venit înapoi oameni sărind peste înainte! :)
= 0
") și a cărui definiție a vă oferi (nu "`= default"). virtual ~A() = default;
sau
virtual ~A() {}
? Dacă este așa, două etape va schimba destructor în tipul de funcție ne-o dorim. În primul rând, schimba linia de
virtual ~A();
Al doilea, a pus următoarea linie într-un fișier sursă care este parte a proiectului dumneavoastră (de preferință fisierul cu clasa de punere în aplicare, dacă aveți unul):
A::~A() {}
Care face (virtual) destructor non-inline și nu generat de compilator. (Simțiți-vă liber pentru a modifica lucrurile pentru a se potrivi mai bine codul de formatare stil, cum ar fi adăugarea unui antet comentariu la definirea funcției.)
Atât de multe răspunsuri, dar niciunul dintre ei nu părea să fi acoperite care este problema mea. Am avut urmatoarele:
class I {
virtual void Foo()=0;
};
Și într-un alt fișier (inclus în elaborarea și leagă, desigur)
class C : public I{
void Foo() {
//bar
}
};
Ei bine acest lucru nu't de lucru si am primit eroarea toată lumea vorbește despre. Pentru a rezolva aceasta, am avut pentru a muta definiția actuală a Foo din declarația de clasă ca atare:
class C : public I{
void Foo();
};
C::Foo(){
//bar
}
Am'm C++ guru deci nu pot't explica de ce acest lucru este mult mai corectă, dar a rezolvat problema pentru mine.
Așa că am fost folosind Qt cu Windows XP și MinGW compiler și acest lucru a fost de conducere mine nebun.
Practic moc_xxx.cpp a fost generat de gol chiar și atunci când I-a fost adăugat
Q_OBJECT
Ștergerea tot ceea funcții virtuale, explicite și orice ai ghici nici't a lucrat. În cele din urmă am început eliminarea linie cu linie și s-a dovedit că am avut
#ifdef something
În jurul valorii de fișier. Chiar și atunci când #ifdef fost adevărata fișierul nu a fost generat.
Deci eliminarea tuturor #ifdefs rezolvat problema.
Acest lucru nu se întâmplă cu Windows și VS 2013.
Dacă toate altceva nu reușește, uita-te pentru duplicare. Am fost îndrumat greșit de explicit trimitere inițială la constructori și destructori până când am citit-o referință la un alt post. L's any nerezolvate metodă. În cazul meu, am crezut că am avut înlocuit cu declarația pe care a folosit char xml ca parametru cu o utilizează în mod inutil supărătoare const char xml, dar în loc de asta, am creat unul nou și a lăsat-o pe cealaltă în loc.