[Solved] Linkerfehler (ehem. Typkonvertierung?)



  • Was er mit den "operator delete"s will, ist mir auch nicht klar. Verwendest du vielleicht etwas weiter oben in der Hierarchie new/delete?

    Die ": undefined reference to `vtable for TExec'" hängt vermutlich damit zusammen, daß du den TExec::operator() nicht definiert hast. Der Compiler legt dir implizit eine VTable an (um später die virtuellen Methodenaufrufe aufdröseln zu können), allerdings muß er dazu wissen, in welcher Übersetzungseinheit er sie unterbringen soll. Die übliche Lösung dazu ist, sie in der gleichen ÜE zu definieren wie die erste virtuelle Methode der Klasse - und genau die hast du weggelassen.



  • CStoll schrieb:

    Was er mit den "operator delete"s will, ist mir auch nicht klar. Verwendest du vielleicht etwas weiter oben in der Hierarchie new/delete?

    Kurze Antwort: nein. Der einzige Teil der KLassenhierarchie, den ich nicht mitgeliefert habe, ist eine zweizeilige klassendefinition von TPrimitive sowie ein oder zwei typedefs (Classname ist nichts weiter als std::string)

    class TPrimitive
    {
    public:
      virtual const Classname isA() const;
      virtual ~TPrimitive() {};
    };
    

    CStoll schrieb:

    Die ": undefined reference to `vtable for TExec'" hängt vermutlich damit zusammen, daß du den TExec::operator() nicht definiert hast. Der Compiler legt dir implizit eine VTable an (um später die virtuellen Methodenaufrufe aufdröseln zu können), allerdings muß er dazu wissen, in welcher Übersetzungseinheit er sie unterbringen soll. Die übliche Lösung dazu ist, sie in der gleichen ÜE zu definieren wie die erste virtuelle Methode der Klasse - und genau die hast du weggelassen.

    Hatte mal gelesen dass es sowas wie "pure virtual" Methoden gibt -> man kann Methoden als virtuell deklarieren, muss sie aber erst in den abgeleiteten KLassen definieren, wenn man die Basisklasse nicht direkt verwendet. War das eine Fehlinformation? Werd mich mal dranmachen, die fehlenden Konstruktoren (an denen es nicht liegen kann) und die fehlenden Definitionen der virtuellen Methoden und Operatoren (an denen es genauso wenig liegen wird?) hinzuferkeln...

    ps: mein Compiler ist der gcc 3.3.3 fuer i686-pc-linux-gnu, vielleicht ist da was bekannt in der RIchtung? (glaube ich aber eigentlich nicht)



  • Wäre es möglich das du TPrimitive auch mal postest ?
    Edit: Danke 😉



  • pumuckl schrieb:

    Hatte mal gelesen dass es sowas wie "pure virtual" Methoden gibt -> man kann Methoden als virtuell deklarieren, muss sie aber erst in den abgeleiteten KLassen definieren, wenn man die Basisklasse nicht direkt verwendet.

    Ne ist schon so eigentlich richtig. Deine op's() in TExec und TPrimitive schreien schon danach pure virtual zu sein:

    virtual const Classname isA() const = 0;
    //...
    virtual void operator() (TPrimitive& result, std::vector<TPrimitive*> arglist) const = 0;
    


  • KasF schrieb:

    Wäre es möglich das du TPrimitive auch mal postest ?

    siehe oben 🙂

    weitere Erkenntnisse: Ich hab mein main() jetzt nur auf die ersten 2-3 Zeilen reduziert (Definitionen der TInt's a b und c) - er spuckt mir immernoch ins Gesicht:

    /tmp/ccT1pvrf.o(.gnu.linkonce.t._ZN4TIntD1Ev+0x2d): In function `TInt::~TInt [in-charge]()':
    : undefined reference to `operator delete(void*)'
    /tmp/ccT1pvrf.o(.gnu.linkonce.t._ZN10TPrimitiveD2Ev+0x22): In function `TPrimitive::~TPrimitive [not-in-charge]()':
    : undefined reference to `operator delete(void*)'
    /tmp/ccT1pvrf.o(.gnu.linkonce.t._ZN4TIntD0Ev+0x2d): In function `TInt::~TInt [in-charge deleting]()':
    : undefined reference to `operator delete(void*)'
    /tmp/ccT1pvrf.o(.gnu.linkonce.t._ZNK4TInt3isAEv+0xe): In function `TInt::isA() const':
    : undefined reference to `std::allocator<char>::allocator[in-charge]()'
    /tmp/ccT1pvrf.o(.gnu.linkonce.t._ZNK4TInt3isAEv+0x28): In function `TInt::isA() const':
    : undefined reference to `std::basic_string<char, std::char_traits<char>, std::allocator<char> >::basic_string[in-charge](char const*, std::allocator<char> const&)'
    /tmp/ccT1pvrf.o(.gnu.linkonce.t._ZNK4TInt3isAEv+0x33): In function `TInt::isA() const':
    : undefined reference to `std::allocator<char>::~allocator [in-charge]()'
    /tmp/ccT1pvrf.o(.gnu.linkonce.t._ZNK4TInt3isAEv+0x46): In function `TInt::isA() const':
    : undefined reference to `std::allocator<char>::~allocator [in-charge]()'
    /tmp/ccT1pvrf.o(.gnu.linkonce.r._ZTI4TInt+0x0): undefined reference to `vtable for __cxxabiv1::__si_class_type_info'
    /tmp/ccT1pvrf.o(.gnu.linkonce.t._ZNK10TPrimitive3isAEv+0xe): In function `TPrimitive::isA() const':
    : undefined reference to `std::allocator<char>::allocator[in-charge]()'
    /tmp/ccT1pvrf.o(.gnu.linkonce.t._ZNK10TPrimitive3isAEv+0x28): In function `TPrimitive::isA() const':
    : undefined reference to `std::basic_string<char, std::char_traits<char>, std::allocator<char> >::basic_string[in-charge](char const*, std::allocator<char> const&)'
    /tmp/ccT1pvrf.o(.gnu.linkonce.t._ZNK10TPrimitive3isAEv+0x33): In function `TPrimitive::isA() const':
    : undefined reference to `std::allocator<char>::~allocator [in-charge]()'
    /tmp/ccT1pvrf.o(.gnu.linkonce.t._ZNK10TPrimitive3isAEv+0x46): In function `TPrimitive::isA() const':
    : undefined reference to `std::allocator<char>::~allocator [in-charge]()'
    /tmp/ccT1pvrf.o(.gnu.linkonce.t._ZN10TPrimitiveD1Ev+0x22): In function `TPrimitive::~TPrimitive [in-charge]()':
    : undefined reference to `operator delete(void*)'
    /tmp/ccT1pvrf.o(.gnu.linkonce.t._ZN10TPrimitiveD0Ev+0x22): In function `TPrimitive::~TPrimitive [in-charge deleting]()':
    : undefined reference to `operator delete(void*)'
    /tmp/ccT1pvrf.o(.gnu.linkonce.r._ZTI10TPrimitive+0x0): undefined reference to `vtable for __cxxabiv1::__class_type_info'
    /tmp/ccT1pvrf.o(.eh_frame+0x12): undefined reference to `__gxx_personality_v0'
    

    Allmaehlich krieg ich den bloeden Eindruck dass er so rein garnichts von alleine mitlinkt, dass ich ihm irgendwelche Grundlegenden Kleinigkeiten explizit zum Linken mit angeben muss 😞



  • pumuckl schrieb:

    weitere Erkenntnisse: Ich hab mein main() jetzt nur auf die ersten 2-3 Zeilen reduziert (Definitionen der TInt's a b und c) - er spuckt mir immernoch ins Gesicht:
    [code]/tmp/ccT1pvrf.o(.gnu.linkonce.t._ZN4TIntD1Ev+0x2d): In function `TInt::~TInt [in-charge]()':
    : undefined reference to `operator delete(void*)'
    /tmp/ccT1pvrf.o(.gnu.linkonce.t._ZN10TPrimitiveD2Ev+0x22): In function `TPrimitive::~TPrimitive [not-in-charge]()':
    : undefined reference to `operator delete(void*)'
    /tmp/ccT1pvrf.o(.gnu.linkonce.t._ZN4TIntD0Ev+0x2d): In function `TInt::~TInt [in-charge deleting]()':
    : undefined reference to `operator delete(void*)'
    /tmp/ccT1pvrf.o(.gnu.linkonce.t._ZNK4TInt3isAEv+0xe): In function `TInt::isA() const':
    : undefined reference to `std::allocator<char>::allocator[in-charge]()'
    /tmp/ccT1pvrf.o(.gnu.linkonce.t._ZNK4TInt3isAEv+0x28): In function `TInt::isA() const':
    : undefined reference to `std::basic_string<char, std::char_traits<char>, std::allocator<char> >::basic_string[in-charge](char const*, std::allocator<char> const&)'
    /tmp/ccT1pvrf.o(.gnu.linkonce.t._ZNK4TInt3isAEv+0x33): In function `TInt::isA() const':
    : undefined reference to `std::allocator<char>::~allocator [in-charge]()'
    /tmp/ccT1pvrf.o(.gnu.linkonce.t._ZNK4TInt3isAEv+0x46): In function `TInt::isA() const':
    : undefined reference to `std::allocator<char>::~allocator [in-charge]()'
    /tmp/ccT1pvrf.o(.gnu.linkonce.r._ZTI4TInt+0x0): undefined reference to `vtable for __cxxabiv1::__si_class_type_info'
    /tmp/ccT1pvrf.o(.gnu.linkonce.t._ZNK10TPrimitive3isAEv+0xe): In function `TPrimitive::isA() const':
    : undefined reference to `std::allocator<char>::allocator[in-charge]()'
    /tmp/ccT1pvrf.o(.gnu.linkonce.t._ZNK10TPrimitive3isAEv+0x28): In function `TPrimitive::isA() const':
    : undefined reference to `std::basic_string<char, std::char_traits<char>, std::allocator<char> >::basic_string[in-charge](char const*, std::allocator<char> const&)'
    /tmp/ccT1pvrf.o(.gnu.linkonce.t._ZNK10TPrimitive3isAEv+0x33): In function `TPrimitive::isA() const':
    : undefined reference to `std::allocator<char>::~allocator [in-charge]()'
    /tmp/ccT1pvrf.o(.gnu.linkonce.t._ZNK10TPrimitive3isAEv+0x46): In function `TPrimitive::isA() const':
    : undefined reference to `std::allocator<char>::~allocator [in-charge]()'
    /tmp/ccT1pvrf.o(.gnu.linkonce.t._ZN10TPrimitiveD1Ev+0x22): In function `TPrimitive::~TPrimitive [in-charge]()':
    : undefined reference to `operator delete(void*)'
    /tmp/ccT1pvrf.o(.gnu.linkonce.t._ZN10TPrimitiveD0Ev+0x22): In function `TPrimitive::~TPrimitive [in-charge deleting]()':
    : undefined reference to `operator delete(void*)'
    /tmp/ccT1pvrf.o(.gnu.linkonce.r._ZTI10TPrimitive+0x0): undefined reference to `vtable for __cxxabiv1::__class_type_info'
    /tmp/ccT1pvrf.o(.eh_frame+0x12): undefined reference to `__gxx_personality_v0'
    

    😕 Kann ich jetzt nichts zu sagen, aber was anderes:

    template<class Func, class T> class TBinaryExec : public TExec
    {
    public:
      virtual void operator() (TPrimitive& result, std::vector<TPrimitive*> arglist) const
        {
          Func binfct;
          T& res = static_cast<T&>(result);
          res = binfct(static_cast<T&>(*arglist[0]), static_cast<T&>(*arglist[1]));
          return;
        };
      ~TBinaryExec() {};
    
    };
    

    Spar die hier dein zweiten Templateparameter, indem du es so machst:

    template<class Func> class TBinaryExec : public TExec
    {
    public:
      typedef typename Func::result_type T;
    virtual void operator() (TPrimitive& result, std::vector<TPrimitive*> arglist) const
        {
          Func binfct;
          T& res = static_cast<T&>(result);
          res = binfct(static_cast<T&>(*arglist[0]), static_cast<T&>(*arglist[1]));
          return;
        };
      ~TBinaryExec() {};
    
    };
    

    Ist auch sicherer und konsistenter.



  • stimmt, sieht schoener aus.

    ich hab jetzt mal aus volkards kleinem Tutorial das Hello World ausgeschnipselt und dem Compiler zu fressen gegeben:

    #include <iostream.h>
    int main()
    {
      cout << "Hallo Welt!" << endl;
    };
    

    Die erste Meldung versteh ich ja noch:

    In file included from /opt/products/gcc/3.3.3/include/g++-3/backward/iostream.h:31,
                     from hallowelt.cpp:2:
    /opt/products/gcc/3.3.3/include/g++-3/backward/backward_warning.h:32:2: warning: #warning This file includes at least one deprecated or antiquated header. Please consider using one of the 32 headers found in section 17.4.1.2 of the C++ standard. Examples include substituting the <X> header for the <X.h> header for C++ includes, or <sstream> instead of the deprecated header <strstream.h>. To disable this warning use -Wno-deprecated.
    

    Aber dann kommt das Biest mit folgendem:

    /tmp/ccbQP0IY.o(.text+0x1b): In function `main':
    : undefined reference to `std::cout'
    /tmp/ccbQP0IY.o(.text+0x20): In function `main':
    : undefined reference to `std::basic_ostream<char, std::char_traits<char> >& std::operator<< <std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char> >&, char const*)'
    /tmp/ccbQP0IY.o(.text+0x28): In function `main':
    : undefined reference to `std::basic_ostream<char, std::char_traits<char> >& std::endl<char, std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char> >&)'
    /tmp/ccbQP0IY.o(.text+0x30): In function `main':
    : undefined reference to `std::basic_ostream<char, std::char_traits<char> >::operator<<(std::basic_ostream<char, std::char_traits<char> >& (*)(std::basic_ostream<char, std::char_traits<char> >&))'
    /tmp/ccbQP0IY.o(.text+0x59): In function `__static_initialization_and_destruction_0(int, int)':
    : undefined reference to `std::ios_base::Init::Init[in-charge]()'
    /tmp/ccbQP0IY.o(.text+0x74): In function `__static_initialization_and_destruction_0(int, int)':
    : undefined reference to `std::ios_base::Init::~Init [in-charge]()'
    /tmp/ccbQP0IY.o(.eh_frame+0x11): undefined reference to `__gxx_personality_v0'
    

    Das halte ich dann doch schon fuer sehr peinlich 🙄

    Allerdings kommt das nur wenn ich ihn mit

    gcc hallowelt.cpp
    

    aufrufe. Nutze ich stattdessen g++, tut ers einwandfrei. Was ist da jetzt schief gelaufen? Hab ich die ganze Zeit meinen Compiler falsch behandelt? Ist er mir jetzt boese? *Kopf->Tisch*



  • pumuckl schrieb:

    ...
    Die erste Meldung versteh ich ja noch:

    In file included from /opt/products/gcc/3.3.3/include/g++-3/backward/iostream.h:31,
                     from hallowelt.cpp:2:
    /opt/products/gcc/3.3.3/include/g++-3/backward/backward_warning.h:32:2: warning: #warning This file includes at least one deprecated or antiquated header. Please consider using one of the 32 headers found in section 17.4.1.2 of the C++ standard. Examples include substituting the <X> header for the <X.h> header for C++ includes, or <sstream> instead of the deprecated header <strstream.h>. To disable this warning use -Wno-deprecated.
    

    ...

    Beheb' die doch erstmal !
    iostream.h -> iostream

    Gruß,

    Simon2.



  • JUHU! ES KLAPPT!

    1. g++ statt gcc verwendet, auf einmal kennt er den ganzen Mist!
    2. std::ostream& operator<<(std::ostream, TInt) richtig definiert (war wohl keinem aufgefallen 🙂
    3. natuerlich auf den richtigen iostream header umgestiegen
    4. Kompiliert => funktioniert alles wie gewuenscht. Danke denen, die sich die Muehe gegeben haben, den Fehler mit einzugrenzen.


  • Ein richtiges Hello World Programm sieht für mich so aus:
    [code]
    #include <iostream>

    int main()
    {
    std::cout << "Hello World" << std::endl;
    cin.get();
    }



  • bzw return 0; darf für mich nicht fehlen 😃

    #include <iostream>
    
    int main()
    {
    std::cout << "Hello World" << std::endl;
    cin.get();
    return 0;
    }
    


  • pumuckl schrieb:

    JUHU! ES KLAPPT!

    1. g++ statt gcc verwendet, auf einmal kennt er den ganzen Mist!

    Jaja, es kann schon Wunder bewirken, wenn man ein C++ Programm auch durch einen C++ Compiler jagt 😃 (der gcc ist ein C-Compiler)



  • ... für einen C-Compiler hat er aber unheimlich viel C++ verstanden *grml* 😉
    Naja, wieder so ein Fehler, den man genau einmal macht *fg*

    Wenn ichs richtig mitbekommen hab, ist g++ auch nur gcc mit ein paar zusätzlichen Linker optionen?



  • pumuckl schrieb:

    Wenn ichs richtig mitbekommen hab, ist g++ auch nur gcc mit ein paar zusätzlichen Linker optionen?

    Nein. C und C++ sind zwei Unterschiedliche Sprachen.

    Genauso ist der gcj kein gcc "mit ein paar zusätzlichen Linkeroptionen" 😉



  • pumuckl schrieb:

    ...Wenn ichs richtig mitbekommen hab, ist g++ auch nur gcc mit ein paar zusätzlichen Linker optionen?

    Früher (vor der Standardisierung) gab's mal "C++2C-Präprozessoren", die C++-Code in C-Code wandelten und den dann durch einen C-Compiler jagten ... aber die Zeiten sind schon länger vorbei.

    Aber gräme Dich nicht: Der Irrglaube C++ sei "eigentlich C" ist leider recht weit verbreitet. 😃

    Gruß,

    Simon2.



  • mir ist durchaus bekannt, dass C und C++ zwei verschiedene Sprachen sind. Ich habe grade mal auf http://gcc.gnu.org nachgestöbert und meien vage Erinnerung halbwegs bestätigt gefunden, dass mit "gcc"-Aufruf keineswegs nur der C-Compiler aufgerufen wird. gcc steht für Gnu Compiler Collection und der Guteste ist so nett, anhand der Dateiendungen zu unterscheiden, welchen seiner eingebauten Compiler er bemüht, z.B. den Fortran Compiler für Source mit Dateiendung .f, C-Compiler für .c, C++-Compiler für .C, .cpp, .cxx .c++ usw.

    However, the use of gcc does not add the C++ library. g++ is a program that calls GCC and treats .c',.h' and .i' files as C++ source files instead of C source files unless -x is used, **and automatically specifies linking against the C++ library.** This program is also useful when precompiling a C header file with a.h' extension for use in C++ compilations. On many systems, g++ is also installed with the name c++.

    Im gewissen Sinne also doch gcc plus Linkeroptionen und ein paar Kleinigkeiten, da gcc eben NICHT nur ein C-Compiler ist...



  • pumuckl schrieb:

    mir ist durchaus bekannt, dass C und C++ zwei verschiedene Sprachen sind....

    Sorry, da habe ich mich unklar ausgedrückt. Ich meinte nicht Dich, sondern Deine Quellen, die evtl. diesen Fehler gemacht haben. Ich habe das einfach schon so oft in Internet gelesen, dass ich mich wundere, dass überhaupt noch jemand die Wahrheit kennt 😉

    Die Erfahrung mit den "Dateienden" beim gcc habe ich auch schon bitter gemacht ... mag für einige praktisch sein, aber ich finde es eher fehlerträchtig.

    Gruß,

    Simon2.


Anmelden zum Antworten