c ++ riferimento indefinito a vtable

Sto imparando C ++. Sto provando a fare un esercizio in cui definisco diverse implementazioni di una pura class virtuale con una singola funzione. Ho problemi a colbind la class che utilizza queste implementazioni.

==> BasicMath.h <== #ifndef BASIC_MATH_H #define BASIC_MATH_H #include #include class BasicMath { }; #endif // BASIC_MATH_H ==> Operation.h <== #ifndef OPERATION #define OPERATION #include #include class Operation { public: virtual void perform(std::vector vec) = 0; }; #endif // OPERATION ==> Sum.h <== #ifndef SUM_H #define SUM_H #include "Operation.h" class Sum: public Operation { public: void perform(std::vector vec); }; #endif // SUM_H ==> BasicMath.cpp <== #ifndef BASIC_MATH_C #define BASIC_MATH_C #include  #include  #include  #include "BasicMath.h" #include "Sum.h" int main(int argc, char* argv[]) { Sum op; } #endif // BASIC_MATH_C ==> Sum.cpp <== #ifndef SUM_C #define SUM_C #include  #include  #include  #include "Sum.h" void Sum::perform(std::vector vec) { using namespace std; int total = 0; cout << "Total: " << total << "\n"; }; #endif // SUM_C 

Compilazione:

 $ g++ -c Sum.cpp $ g++ -o BasicMath BasicMath.cpp /tmp/cc1VXjNl.o:BasicMath.cpp:(.text$_ZN3SumC1Ev[Sum::Sum()]+0x16): undefined reference to `vtable for Sum' collect2: ld returned 1 exit status 

Sono sicuro al 95% che sto facendo almeno una cosa sciocca qui – ma il mio cervello si rifiuta di dirmi cosa.

Ho visto questa domanda ma non sono riuscito a risolvere il mio problema.

Non includi il file object Sum.o sulla tua riga di compilazione e collegamento (secondo uso di g ++).

Ho appena incontrato lo stesso problema, ma il mio problema era che non avevo scritto il codice del distruttore nel mio file .cpp.

class.h:

 class MyClass { public: MyClass(); virtual ~MyClass(); }; 

class.cpp:

 MyClass::MyClass() {} 

Mi ha appena dato il messaggio di errore vtable e l’implementazione del distruttore (vuoto) ha risolto il problema.

[Modifica] Pertanto, il file di class corretto ha il seguente aspetto:

 MyClass::MyClass() {} MyClass::~MyClass() {} 

Un paio di persone hanno già indicato la soluzione al problema che hai visto.

Aggiungerò qualcosa di diverso. Hai solo bisogno di guardie di testa nelle tue intestazioni. Li hai inclusi anche nei tuoi file sorgente , dove in realtà non hanno senso. Ad esempio, ho commentato le righe di cui non hai davvero bisogno (o nemmeno vuoi) in sum.cpp:

 //#ifndef SUM_C //#define SUM_C // #include  #include  #include  #include "Sum.h" void Sum::perform(std::vector vec) { using namespace std; int total = 0; cout << "Total: " << total << "\n"; }; //#endif // SUM_C 

Solo FWIW, invece di perform , userei operator() :

 class Operation { public: virtual void operator()(std::vector vec) = 0; }; 

e (ovviamente) questo è anche ciò che potresti sovraccaricare per Sum . Per usarlo, invece di qualcosa di simile:

 Sum op; op.perform(); 

Dovresti usare qualcosa come:

 Sum op; op(); 

Ciò è particolarmente comodo quando si combina la class con altre (ad es. Quelle della libreria standard) che invocano operazioni come le funzioni, siano esse realmente funzioni o "funzioni" (classi come questa, quell'operatore di overload operator() così sintatticamente può essere usato quasi come funzioni).

Questo errore si verifica anche se si dimentica il = 0 per le funzioni virtuali pure

Errore:

 class Base { public: virtual void f(); }; class Derived : public Base { public: virtual void f() {} }; int main() { Derived d; Base *b = &d; } 

Nessun errore:

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

Questo perché senza il valore = 0 , il C ++ non sa che è una pura funzione virtuale, lo tratta come una dichiarazione, aspettandosi una definizione successiva.

Testato su g++ 5.2.1.

Stai semplicemente compilando BasicMath.cpp senza Sum.cpp – il tuo linker non ha idea di Sum.cpp. Dovrai compilarli entrambi insieme, cioè Sum.cpp BasicMath.cpp in una volta sola, oppure puoi compilare i file .cpp in modo indipendente e quindi creare l’eseguibile chiamando g ++ con entrambi i file .o.

Normalmente incontro questo errore quando dimentico per errore =0 alla fine di una delle mie funzioni in una pura class virtuale.