Problem: operator<<
-
class Base{ public: Base& operator<<(const int& rhs) { /*blabla*/ return *this; } }; class Derived : public Base{ public: Derived & operator<<(const std::string& rhs) { /*blabla*/ return *this; } using Base::operator<<; }; int main(){ Derived b; b << "hallo" << 1; //funzt b << 1 << "hallo"; //funzt nicht, weil er eine Base-Referenz nach b << 1 zurück gibt return 0; }Wie kann man das Problem lösen OHNE alle Operatoren in der abgeleiteten Klasse erneut zu implementieren?
Sowas möchte ich natürlich umgehenst vermeiden:
Derived & operator<<(const int& rhs) { return dynamic_cast<Derived&>Base::operator<<( rhs ); }
-
Template vielleicht... ?
-
#include <iostream> class Base{ public: template <typename T> Base& operator<<(const T& rhs) { /*blabla*/ return *this; } }; class Derived : public Base{ public: template <typename T> Derived & operator<<(const T& rhs) { /*blabla*/ return *this; } using Base::operator<<; }; int main() { Derived b; b << "hallo" << 1; //funzt b << 1 << "hallo"; //funzt nicht, weil er eine Base-Referenz nach b << 1 zurück gibt return 0; }Tätätääää
-
Das beste, was mir dazu einfällt, ist die curiously recurring template pattern, d.h.
template<typename actual_t> class base { actual_t &operator<<(int x) { /* ... */ return static_cast<actual_t&>(*this); } }; class derived : public base<derived> { // ... };Insgesamt ist das kein Problem, dass sich über objektorientierte Polymorphie lösen lässt. Nimm beispielsweise
void foo(Base &bar) { bar << 1 << "foo"; }...und schmeiß da ein Objekt einer zur Laufzeit ausgewählten, von Base abgeleiteten Klasse rein. Woher soll der Compiler wissen, ob die abgeleitete Klasse den String-Operator überhaupt hat?
-
Der Ansatz ist verkehrt.
Was willst du denn erreichen damit?
-
Hi shadow
class Base{ public: virtual ~Base() {} template< typename T > Base& operator<<( const T& t ) { os << "örx"; return *this; }; Base& operator<<(const int& rhs) { os << rhs; return *this; } Base& operator<<(const double & rhs) { os << rhs; return *this; } void print() { std::cout << os.str() << std::endl; } public: std::ostringstream os; }; class Derived : public Base{ public: //Derived & operator<<(const std::wstring& rhs) { os << rhs; return *this; } Derived & operator<<(const std::string& rhs) { os << rhs; return *this; } Derived & operator<<(const char* & rhs) { os << rhs; return *this; } template< typename T > Derived & operator<<( const T& t ) { return dynamic_cast<Derived&>( Base::operator<<( t ) ); } using Base::operator<<; };also so geht das def nicht.
jedenfalls stellt die klasse ein archiv da. in der basisklasse sollen alle fundamentalen datentypen behandelt werden und in den speziellen eben spezielle klassen. aber man möchte ein casten vermeiden, so dass sowas immer geht:Derived d; d << fundamental << speziell << speziell << fundamental ;letztelich fügt man immer eine grosse anzahl an elementen an...
-
Was genau stellt Base denn da? Eine Art Serialisierung?
Ich wuerde den operator<< einfach aus der Klasse rausziehen, er fuehlt sich dort eh nicht gut an. Alternativ wie seldon gesagt hat: CRTP.
Prinzipiell will man aber hier eine Trennung zwischen der Klasse die die Daten speichert und den Operatoren des einfuegens. Meistens macht man es so, dass die Klasse die in das Archiv eingefuegt wird die Operation selber unterstuetzen muss. Da das manchmal unpraktisch ist, laesst man eine 3. Entitaet das Uebernehmen.
Hier ist es zB simpel: einfach den operator<< als freie Funktion definieren.
-
ja, allerdings ist das nicht mein code

in boost bzw der rcf von jarl lindrud mache ich es ebenfalls so. jede klasse serialisiert sich selbst... aber das geht hier eben nicht.
ich schau einfach mal, wie ich es am besten hinbekomme... danke erstmal
vermutlich werde ich das curiously recurring template pattern anwenden.