[Solved] Linkerfehler (ehem. Typkonvertierung?)
-
Eine Lösung wäre es, schon die Basisklasse als Template anzulegen (d.h. sie verwendet nicht mehr den vorgegebenen TPrimitive, sondern den jeweils gültigen Argumenttyp als Parameter.
Zu den Linkerfehlern: Du hast zwar den Destruktor und operator() in der TExec deklariert, aber offenbar hast du die zugehörigen Definitionen vergessen (den Operator könntest du noch pur virtuell definieren, aber den Destruktor brauchst du auf jeden Fall).
-
Das Problem an der Sache ist, dass ich Pointer auf mehrere Ableitungen von TExec in einem Container lagern will und den operator() der entsprechenden Objekte auf die angegebene Art und Weise aufrufen will, ohne vorher genau zu wissen, welche Ableitungen von TPrimitive dabei genau zum Tragen kommen. Deshalb kann ich TExec nicht als Templateklasse definieren, zumal da eh auch gemischte Parameterlisten für operator() zulässig sein sollen, also z.B.
class TInt : public TPrimitive; class TFloat : public TPrimitive; class MixedArgs : public TExec; TInt a; TFloat b; TFloat c; std::vector<TPrimitive*> arglist; arglist.push_back(&a); arglist.push_back(&b); MixedArgs myexec; myexec(c, arglist);Was die Linkerfehler angeht: die Definition der Destruktoren hatte ich tatsächlich übersehn, aber auch nachdem ich die nachgeliefert habe meckert er über "undefined reference to 'operator delete(void*)'" - was mir nicht mehr so ganz einleuchtet.
-
Warum er operator delete nicht findet weiss ich nicht.
Aber: dynamic_cast bringt dir so wie du das verwendest garnix, denn dynamic_cast mit Zeigern liefert einfach einen null pointer zurück (wenn die Konvertierung nicht möglich ist bzw. nicht erlaubt ist), wodurch dein Programm an der Stelle schön abschmieren wird. Kannst du gleich static_cast verwenden.
Oder aber du verwendest dynamic_cast mit Referenzen (dann fliegt ne Exception wenn die Konvertierung nicht hinhaut), oder du solltest den Returnwert vorher prüfen (wenn du dynamic_cast mit Zeigern verwenden willst).
z.B.:// result = binfct(*dynamic_cast<T*>(arglist[0]), *dynamic_cast<T*>(arglist[1])); // -> result = binfct(dynamic_cast<T&>(*arglist[0]), dynamic_cast<T&>(*arglist[1]));
-
Okay, danke. dann muss ich mir die genauere Verwendung der cast-Operatoren nochmal anschauen - vielleicht gibt sich das mit dem delete(void*) dann auch von alleine

-
Ich habs jetzt auf static_cast umgestellt und noch einen kleinen Fehler entdeckt - die Fehlermeldungen sind aber leider noch vorhanden:
//TPrimitive.hpp class TInt : public TPrimitive { private: long int _i; public: // Ctor TInt() : _i(0) {}; TInt(const TInt& ti) : _i(ti._i) {}; TInt(const long int i) : _i(i) {}; // Dtor ~TInt() {}; // Operators TInt& operator= (const long int& i) { _i = i; return *this;}; TInt& operator= (const TInt& ti) { _i = ti._i; return *this;}; std::ostream& operator<<(std::ostream& os) {os << _i; return os;}; TInt operator+ (const TInt& ti2) const {return TInt(_i+ti2._i);}; inline const Classname isA() const {return "TInt";}; }; //TExec.hpp class TExec { public: virtual void operator() (TPrimitive& result, std::vector<TPrimitive*> arglist) const; virtual ~TExec() {}; }; 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() {}; }; //main() int main() { TInt a = 5; TInt b = 6; TInt c; TBinaryExec<std::plus<TInt>, TInt> exec; std::vector<TPrimitive*> arglist; arglist.push_back(&a); arglist.push_back(&b); exec(c, arglist); };ergibt
testprg.o(.gnu.linkonce.t._ZN11TBinaryExecISt4plusI4TIntES1_ED1Ev+0x2d): In function `TBinaryExec<std::plus<TInt>, TInt>::~TBinaryExec [in-charge]()': : undefined reference to `operator delete(void*)' testprg.o(.gnu.linkonce.t._ZN4TIntD1Ev+0x2d): In function `TInt::~TInt [in-charge]()': : undefined reference to `operator delete(void*)' testprg.o(.gnu.linkonce.t._ZN5TExecD2Ev+0xb): In function `TExec::~TExec [not-in-charge]()': : undefined reference to `vtable for TExec' testprg.o(.gnu.linkonce.t._ZN5TExecD2Ev+0x22): In function `TExec::~TExec [not-in-charge]()': : undefined reference to `operator delete(void*)' testprg.o(.gnu.linkonce.t._ZN11TBinaryExecISt4plusI4TIntES1_ED0Ev+0x2d): In function `TBinaryExec<std::plus<TInt>, TInt>::~TBinaryExec [in-charge deleting]()': : undefined reference to `operator delete(void*)'usw.
WAS WILL DER VON MIR??? *verzweifelt*
-
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.cppaufrufe. 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 -> iostreamGruß,
Simon2.
-
JUHU! ES KLAPPT!
- g++ statt gcc verwendet, auf einmal kennt er den ganzen Mist!
- std::ostream& operator<<(std::ostream, TInt) richtig definiert (war wohl keinem aufgefallen

- natuerlich auf den richtigen iostream header umgestiegen
- 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!
- 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.