2011-01-04 10 views
6

gsoap mit seinen Werkzeugen wsdl2h und soapcpp2 mir enthält, mit einer soapStub.h Datei zur Verfügung gestellt folgenden:undefined reference to Vtable - virtuelles Element generierten Klassen von gsoap

class SOAP_CMAC ns2__SOAPKunden 
{ 
    public: 
    std::string *adresszusatz; 
    // ... 
    public: 
    virtual int soap_type() const { return 7; } 
    // ... 
    ns2__SOAPKunden() : adresszusatz(NULL), x(NULL) { } // left out all member init. 
    virtual ~ns2__SOAPKunden() { } 
}; 

Ich beginne mit einer kleinen App der Klasse mit um Objekte mit Daten aus der informix DB zu füllen.

Aber erfolgreich kompilieren ich alle virtuellen Sachen verlassen müssen weg - ich habe viele Buchungen über diesen Fehler und die Verwendung von virtuellen Mitglieder in Subklassen gefunden - sonst bekomme ich

main.o: In function `ns2__SOAPKunden::ns2__SOAPKunden()': 
main.cpp:(.text._ZN15ns2__SOAPKundenC1Ev[ns2__SOAPKunden::ns2__SOAPKunden()]+0xf): undefined reference to `vtable for ns2__SOAPKunden' 
main.o: In function `ns2__SOAPKunden::~ns2__SOAPKunden()': 
main.cpp:(.text._ZN15ns2__SOAPKundenD1Ev[ns2__SOAPKunden::~ns2__SOAPKunden()]+0x13): undefined reference to `vtable for ns2__SOAPKunden' 
collect2: ld returned 1 exit status 

ich erst nach Jahren von Scripting zulassen Es ist sehr schwer für mich, C++ - Code zu verstehen ... Ich möchte um Rat fragen, was ich als nächstes versuchen soll. Meine Klasse ist keine abgeleitete Klasse, was zum Beispiel mich wundern lässt.

+0

Wenn Sie keine abgeleiteten Klassen verwenden, warum ist die Funktion virtuell? –

Antwort

14

Der Fehler bedeutet, dass die virtuelle Tabelle in der endgültigen Binärdatei (ausführbare Datei oder Bibliothek) nicht korrekt kompiliert/verknüpft wurde. Es gibt zwei allgemeine Umstände, die zu diesem Fehler führen:

  • Sie verknüpfen nicht die Objektdatei, die die virtuellen Tabellendefinitionen enthält - i.e. Sie kompilierten soapStub.cpp in soapStub.o, aber fügten diese Binärdatei der Linker-Befehlszeile nicht hinzu.
  • Der Compiler erzeugt die virtuelle Tabelle nirgends, so dass selbst wenn Sie alle Objektdateien einschließen, die virtuelle Tabelle nicht enthalten ist.
  • Der zweite Fall ist am schwierigsten für nicht erfahrene Entwickler zu identifizieren und kann durch eine Klasse verursacht werden, die im Header definiert ist und virtuelle Funktionen enthält. Wenn alle virtuellen Funktionen inline definiert sind, generiert der Compiler die virtuelle Tabelle in allen Übersetzungseinheiten, die den Header enthalten, und markiert sie als schwaches Symbol, damit der Linker sie verwerfen kann. Wenn Sie jedoch später eine neue virtuelle Methode hinzufügen und Wenn Sie die Definition in einer der virtuellen Funktionen entfernen, wird der Compiler die virtuelle Tabelle nicht in jeder Übersetzungseinheit erzeugen, sondern nur in derjenigen, die diese Funktionen definiert.

    Dinge zu überprüfen:

    • Sie verknüpfen alle Objektdateien
    • entweder alle virtuellen Funktionen inline in der Klassendefinition definiert sind, oder Sie haben eine CPP, die die virtuellen Funktionen definiert und Sie verknüpfen, dass . in
    +2

    Das Problem kann sein, dass man den Destruktor in der abgeleiteten Klasse deklariert, aber nicht definiert hat. Ist diese Situation hier abgedeckt? – Moberg

    +0

    @Moberg: Ja, der zweite Fall. Einige Compiler (gcc unter ihnen) erzeugen die vtable in einer einzigen Übersetzungseinheit. GCC wird die vtable nur in der Übersetzungseinheit definieren, die die * erste * (in Deklarationsreihenfolge) nichtlineare virtuelle Funktion enthält, die in vielen Fällen der Destruktor ist (oft beginnen Klassendefinitionen mit Konstruktoren/Destruktoren) –

    +1

    Clang hat ein ' -Wweak-vtable "Warnung dafür (Ich habe zufällig herausgefunden, wenn Sie" -Weverything "in einer Header-only-Bibliothek versuchen) – TemplateRex

    0

    Dies ist, was sagte David Rodriguez, nur einfacher gesagt ich denke, ...

    habe ich diese Situation in meiner Interface-Klasse:

    class IBase 
    { 
        public: 
        virtual void begin(unsigned long); 
        virtual void end(); 
        virtual int available(void) = 0; 
        virtual int peek(void) = 0; 
        virtual int read(void) = 0; 
        virtual void flush(void) = 0; 
    } 
    

    und verändert es dazu:

    class IBase 
    { 
        public: 
        virtual void begin(unsigned long) = 0; 
        virtual void end() = 0; 
        virtual int available(void) = 0; 
        virtual int peek(void) = 0; 
        virtual int read(void) = 0; 
        virtual void flush(void) = 0; 
    } 
    

    , die der Trick.

    begin() und end() wurden in abgeleiteten Klassen in einer anderen Datei definiert, IBase-Klasse (Schnittstelle) wurde nur im Header deklariert und an wenigen Stellen enthalten.

    Fehler von OP erschien nur, wenn ich Optimierungen auf keine (-O0) gesetzt, jede andere Einstellung führte zu keinem Fehler (gcc 4.8).