2010-11-24 19 views
16

Ich lerne C++. Ich versuche eine Übung zu machen, bei der ich mehrere Implementierungen einer reinen virtuellen Klasse mit einer einzigen Funktion definiere. Ich habe Probleme beim Verknüpfen der Klasse, die diese Implementierungen verwendet.C++ undefined Verweis auf vtable

==> BasicMath.h <== 
#ifndef BASIC_MATH_H 
#define BASIC_MATH_H 

#include<string> 
#include<vector>  

class BasicMath { }; 


#endif // BASIC_MATH_H 

==> Operation.h <== 

#ifndef OPERATION 
#define OPERATION 

#include<string> 
#include<vector>  

class Operation { 
public: 
    virtual void perform(std::vector<std::string> vec) = 0; 
}; 


#endif // OPERATION 

==> Sum.h <== 
#ifndef SUM_H 
#define SUM_H 

#include "Operation.h" 

class Sum: public Operation { 
public: 
    void perform(std::vector<std::string> vec); 
}; 

#endif // SUM_H 

==> BasicMath.cpp <== 
#ifndef BASIC_MATH_C 
#define BASIC_MATH_C 

#include <string> 
#include <vector> 
#include <iostream> 
#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 <vector> 
#include <string> 
#include <iostream> 
#include "Sum.h" 

void Sum::perform(std::vector<std::string> vec) { 
    using namespace std; 
    int total = 0; 
    cout << "Total: " << total << "\n"; 
}; 

#endif // SUM_C 

Compilation:

$ 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 

Ich bin 95% sicher, dass ich zumindest eine dumme Sache hier zu tun - aber mein Gehirn weigert sich, mir zu sagen, was.

Ich habe this Frage gesehen, aber es ist mir nicht gelungen, mein Problem zu beheben.

+1

Seitennotiz: Sie möchten auf jeden Fall einen Std :: Vector als Referenz übergeben, nicht nach Wert. – EboMike

+0

Randnotiz 2: Klassen mit virtuellen Funktionen sollten einen virtuellen Destruktor haben. – EboMike

+0

Ich habe das g ++ -Tag hinzugefügt, da Ihr Problem darin besteht, wie man den Compiler (genauer Linker) zum Verknüpfen von Objektdateien bekommt, und das ist Compiler-abhängig. –

Antwort

16

Sie fügen die Sum.o-Objektdatei nicht in Ihre Kompilierungszeile & ein (zweite Verwendung von g ++).

+0

ok das war quälend einfach. Danke Noah. Nimm die anderen Punkte, vorbei an Ref. Etc. Ich werde als nächstes daran arbeiten, jetzt bin ich über diesen Fehler hinaus. g ++ Handbuch geht auf die Leseliste! – Ben

+0

Richtig, ich habe die 'cpp' Datei einer enthaltenen Klasse nicht kompiliert. – zpon

1

Sie kompilieren nur BasicMath.cpp ohne Sum.cpp - Ihr Linker hat keine Ahnung über Sum.cpp. Sie müssen sie beide zusammen kompilieren, d. H. Sum.cpp BasicMath.cpp auf einmal, oder Sie können die .cpp-Dateien unabhängig voneinander kompilieren und dann die ausführbare Datei erstellen, indem Sie g ++ mit beiden .o-Dateien aufrufen.

5

Ein paar Leute haben bereits auf die Lösung des Problems hingewiesen, das Sie gesehen haben.

Ich füge etwas etwas anderes hinzu. Sie brauchen nur Header-Wächter in Ihren Headern. Sie haben sie auch in Ihre Quelldateien eingefügt, wo sie wirklich nicht Sinn machen. Zum Beispiel habe ich die Zeilen auf Kommentar Sie nicht wirklich brauchen (oder sogar wollen) in sum.cpp:

//#ifndef SUM_C 
//#define SUM_C 
// 
#include <vector> 
#include <string> 
#include <iostream> 
#include "Sum.h" 

void Sum::perform(std::vector<std::string> vec) { 
    using namespace std; 
    int total = 0; 
    cout << "Total: " << total << "\n"; 
}; 

//#endif // SUM_C 

Nur FWIW, statt perform, würde ich verwenden operator():

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

und (offensichtlich) das ist auch, was Sie für Sum überladen würden. Um es zu nutzen, statt so etwas wie:

Sum op; 
op.perform(); 

Sie verwenden würde, so etwas wie: (diejenigen, die in der Standardbibliothek zB)

Sum op; 
op(); 

Dies ist besonders praktisch, wenn Sie Ihre Klasse kombinieren mit anderen diese rufen Operationen wie Funktionen auf, ob sie nun wirklich Funktionen sind oder "Funktoren" (Klassen wie diese, die operator() so syntaktisch überlasten, dass sie fast wie Funktionen verwendet werden können).

+0

Hallo Jerry - Ich habe die Wachen in meiner Quelle hinzugefügt, nachdem ich einige der ACE-Codes überprüft habe, die diesen Stil hatten http://www.cs.wustl.edu/~schmidt/ACE.html. Vielleicht ist dies für einige Frameworks erforderlich oder ist gerade nicht mehr vorhanden? – Ben

1

Ich normalerweise diesen Fehler auftreten, wenn ich versehentlich die =0 am Ende einer meiner Funktionen in einer reinen virtuellen Klasse vergessen.

+0

Das hat damit nichts zu tun. = 0 bedeutet, dass Ihre Klasse abstrakt sein wird. Ich vermute, das Problem ist, dass Sie vergessen haben, einen Funktionskörper zu schreiben. – EboMike

+0

Danke, diese Antwort hat mir geholfen. – maharvey67

19

Ich habe gerade das gleiche Problem, aber mein Problem war, dass ich nicht den Destruktor-Code in meiner .cpp-Datei geschrieben hatte.

class.h:

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

Klasse.cpp:

MyClass::MyClass() {} 

Es gab mir nur die vtable Fehlermeldung, und die Implementierung des (leeren) Destruktors löste das Problem.

[Bearbeiten] So sieht die korrigierte Klassendatei wie folgt aus:

MyClass::MyClass() {} 
MyClass::~MyClass() {} 
+3

Offenbar kann dies häufig genug sein. +1 ... das half mir, das gleiche Problem zu lösen. – IAbstract

+0

Der zweite Codeblock implementiert nicht den (leeren) Destruktor, wie Sie sagen, der den Konstruktor implementiert. – DBedrenko

+1

Der zweite Codeblock zeigte absichtlich den Zustand, der den Fehler verursacht hat. Ich dachte, dass der Satz hinterher für die Lösung ausreichen würde, aber ich fügte den "korrigierten" Inhalt hinzu. –

3

Dieser Fehler geschieht auch, wenn Sie die = 0 für rein virtuelle Funktionen

Fehler vergessen:

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

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

int main() { 
    Derived d; 
    Base *b = &d; 
} 

Kein Fehler:

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

Dies ist, weil ohne die = 0, C++ weiß nicht, dass es eine reine virtuelle Funktion ist, behandelt es als eine Deklaration, erwartet eine spätere Definition.

Getestet an g++ 5.2.1.

+1

Mann, du rettest mein Leben XD – vivi

Verwandte Themen