Abstrakte Klasse Ausgabe Operator überladen



  • Guten Abend.
    Kann mir jemand erklären wie ich eine Operator Überladung mit einer abstrakten Klasse hinbekommen soll 😮 ? Nen Ausgabe Operator.

    main.cpp

    #include <iostream>
    #include "menu.h"
    #include "start menue.h"
    
    using namespace std;
    
    int main()
    {
        start_menue start;
    
    // AM ENDE SOLL DAS  HIER MÖGLICH SEIN
    // cout << start;
    
        return 0;
    }
    

    menu.h

    #ifndef MENU_H_INCLUDED
    #define MENU_H_INCLUDED
    
    #include <iostream>
    
    using namespace std;
    
    class menu{
    public:
        menu(){cout << "Konstruktor  fuer abstrakte klasse" << endl;};
        virtual ~menu() { cout << "Destruktor fuer die abstrakte  klasse " << endl;};
    
        virtual void anzeigen() = 0;
    
          virtual void operator<<(ostream&);
    
    };
    
    #endif // MENU_H_INCLUDED
    

    start menue.h

    #ifndef START_MENUE_H_INCLUDED
    #define START_MENUE_H_INCLUDED
    
    #include "menu.h"
    #include <iostream>
    using namespace std;
    
    class start_menue : public menu{
    public:
        void anzeigen(){
            cout << "Start Menue";
        };
    
        start_menue() : menu() {cout << "Konstruktor fuer Startmenü" << endl;};
    
        ~start_menue(){cout << "Destruktor fuer Startmenü" << endl;};
        void operator<<(ostream&){cout << "Penis";};
    
    };
    #endif // START_MENUE_H_INCLUDED
    


  • was geht denn nicht?

    allgemein macht man die ostream-operatoren als freie funktionen und lässt sie auch denn ensprechenden stream zurückgeben damit man ausgaben verketten kann à la: std::cout << start << '\n';


  • Mod

    So wie du es schreibst, hast du es genau verkehrt rum. Du hast einen Operator<<, der als linkes Argument ein Element deiner Klasse nimmt und als rechtes eine ostream&. Also so:

    start_menu foo;
    foo << cout;
    

    Um es umgekehrt zu machen, müsste die Funktion also entweder ein Member von ostream sein oder aber eine freie Funktion mit den Argumenten in passender Reihenfolge. Da du aber zur Klasse ostream nichts mehr hinzu fügen kannst, bleibt nur letztere Methode. Also freie Funktion:

    ostream& operator<<(ostream&, const deine_klasse&);
    

    Da man in solchen Operatoren oft auch auf private Daten der Klasse zugreifen möchte, wird so etwas häufig entweder mit einer public-Funktion zur Datenausgabe verknüpft (die dann vom Operator aufgerufen wird) oder man macht den Operator zu einem friend der Klasse. In dem Fall kann man den Operator auch inline in der Klassendefinition definieren:

    class foo
    {
      friend ostream& operator<<(ostream &, const foo&) { /* Hier Code */ }
    };
    

    Siehe unter anderem: http://www.c-plusplus.net/forum/232010



  • asfdlol schrieb:

    was geht denn nicht?

    allgemein macht man die ostream-operatoren als freie funktionen und lässt sie auch denn ensprechenden stream zurückgeben damit man ausgaben verketten kann à la: std::cout << start << '\n';

    Ne ich will das ja als operator überladung haben. Einfach so zum spaß xD
    Ich poste mal die mir zumindests nichtssagenden Fehlermeldungen

    Alles aus der menue.h
    Ich frag mich wie Menschen aus so was nur schlau werden xD

    obj/Debug/main.o||In function menu::menu()':| /home/cseipel/Code::Blocks Kram/GTK/test project/abstrakte klassen und vererbung/menu.h|10|undefined reference tovtable for menu'|
    obj/Debug/main.o||In function menu::~menu()':| /home/cseipel/Code::Blocks Kram/GTK/test project/abstrakte klassen und vererbung/menu.h|11|undefined reference tovtable for menu'|
    obj/Debug/main.o:(.rodata._ZTI11start_menue[_ZTI11start_menue]+0x10)||undefined reference to `typeinfo for menu'|
    ||=== Build finished: 3 errors, 0 warnings (0 minutes, 0 seconds) ===|

    obj/Debug/main.o||In function menu::menu()':| /home/cseipel/Code::Blocks Kram/GTK/test project/abstrakte klassen und vererbung/menu.h|10|undefined reference tovtable for menu'|
    obj/Debug/main.o||In function menu::~menu()':| /home/cseipel/Code::Blocks Kram/GTK/test project/abstrakte klassen und vererbung/menu.h|11|undefined reference tovtable for menu'|
    obj/Debug/main.o:(.rodata._ZTI11start_menue[_ZTI11start_menue]+0x10)||undefined reference to `typeinfo for menu'|
    ||=== Build finished: 3 errors, 0 warnings (0 minutes, 0 seconds) ===|

    obj/Debug/main.o||In function menu::menu()':| /home/cseipel/Code::Blocks Kram/GTK/test project/abstrakte klassen und vererbung/menu.h|10|undefined reference tovtable for menu'|
    obj/Debug/main.o||In function menu::~menu()':| /home/cseipel/Code::Blocks Kram/GTK/test project/abstrakte klassen und vererbung/menu.h|11|undefined reference tovtable for menu'|
    obj/Debug/main.o:(.rodata._ZTI11start_menue[_ZTI11start_menue]+0x10)||undefined reference to `typeinfo for menu'|
    ||=== Build finished: 3 errors, 0 warnings (0 minutes, 0 seconds) ===|



  • SeppJ schrieb:

    So wie du es schreibst, hast du es genau verkehrt rum. Du hast einen Operator<<, der als linkes Argument ein Element deiner Klasse nimmt und als rechtes eine ostream&. Also so:

    start_menu foo;
    foo << cout;
    

    Um es umgekehrt zu machen, müsste die Funktion also entweder ein Member von ostream sein oder aber eine freie Funktion mit den Argumenten in passender Reihenfolge. Da du aber zur Klasse ostream nichts mehr hinzu fügen kannst, bleibt nur letztere Methode. Also freie Funktion:

    ostream& operator<<(ostream&, const deine_klasse&);
    

    Da man in solchen Operatoren oft auch auf private Daten der Klasse zugreifen möchte, wird so etwas häufig entweder mit einer public-Funktion zur Datenausgabe verknüpft (die dann vom Operator aufgerufen wird) oder man macht den Operator zu einem friend der Klasse. In dem Fall kann man den Operator auch inline in der Klassendefinition definieren:

    class foo
    {
      friend ostream& operator<<(ostream &, const foo&) { /* Hier Code */ }
    };
    

    Siehe unter anderem: http://www.c-plusplus.net/forum/232010

    Für abstrakte Klassen gibt es leider kein Friend 😞

    Mir gelingt es auch so leider nicht.

    main.cpp

    #include <iostream>
    #include "menu.h"
    #include "start menue.h"
    
    using namespace std;
    
    int main()
    {
        start_menue foo;
        cout << foo;
    
        return 0;
    }
    

    menue.h

    #ifndef MENU_H_INCLUDED
    #define MENU_H_INCLUDED
    
    #include <iostream>
    
    using namespace std;
    
    class menu{
    public:
        menu(){cout << "Konstruktor  fuer abstrakte klasse" << endl;};
        virtual ~menu() { cout << "Destruktor fuer die abstrakte  klasse " << endl;};
    
        virtual void anzeigen() = 0;
    
         virtual ostream& operator<<(ostream&, const menu&);
    
    };
    
    #endif // MENU_H_INCLUDED
    

    start_menu.h

    #ifndef START_MENUE_H_INCLUDED
    #define START_MENUE_H_INCLUDED
    
    #include "menu.h"
    #include <iostream>
    using namespace std;
    
    class start_menue : public menu{
    public:
        void anzeigen(){
            cout << "Start Menue";
        };
    
        start_menue() : menu() {cout << "Konstruktor fuer Startmenü" << endl;};
    
        ~start_menue(){cout << "Destruktor fuer Startmenü" << endl;};
    
        ostream& operator<<(ostream&, const menu&){
            cout << "test";
        }
    
    };
    #endif // START_MENUE_H_INCLUDED
    

    Mal ganz abgesehn davon das start_menue.h sowieso vermutlich wegen

    const menu&

    nicht geht bei

    ostream& operator<<(ostream&, const menu&){
    cout << "test";
    }



  • @Nivea342
    Du kannst den "Ausgabe Operator" nicht als Memberfunktion implementieren. Geht einfach nicht.
    Daher kann man ihn auch nicht überschreiben.

    Was du machen kannst, ist einen "Ausgabe Operator" für die Basisklasse als Funktion zu definieren, die dann einfach nur eine normale Memberfunktion aufruft.
    Diese Memberfunktion kann dann virtual sein, und in abgeleiteten Klassen überschrieben werden:

    #include <iostream>
    using namespace std;
    
    class menu
    {
    public:
        menu() { cout << "Konstruktor fuer abstrakte klasse" << endl; }
        virtual ~menu() { cout << "Destruktor fuer die abstrakte klasse " << endl; }
    
        virtual void anzeigen() = 0;
        virtual void ausgabe_in_stream(ostream& stream) const = 0;
     };
    
    ostream& operator << (ostream& stream, const menu& m)
    {
    	m.ausgabe_in_stream(stream);
    	return stream;
    }
    
    class start_menue : public menu
    {
    public:
    	virtual void anzeigen() { cout << "Start Menue" << endl; }
    
    	~start_menue() { cout << "Destruktor fuer Startmenü" << endl; }
    
    	virtual void ausgabe_in_stream(ostream& stream) const
    	{
    		stream << "stream << start_menue" << endl;
    	} 
    };
    
    class anderes_menue : public menu
    {
    public:
    	virtual void anzeigen() { cout << "Anderes Menue" << endl; }
    
    	~anderes_menue() { cout << "Destruktor fuer anderes Menü" << endl; }
    
    	virtual void ausgabe_in_stream(ostream& stream) const
    	{
    		stream << "stream << anderes_menue" << endl;
    	} 
    };
    
    int main()
    {
    	start_menue start;
     	cout << start;
    
    	anderes_menue a;
    	cout << a;
    
    	return 0;
    }
    

    EDIT: ausgabe_in_stream: cout << "..." -> stream << "..."



  • hustbaer schrieb:

    @Nivea342
    Du kannst den "Ausgabe Operator" nicht als Memberfunktion implementieren. Geht einfach nicht.
    Daher kann man ihn auch nicht überschreiben.

    Was du machen kannst, ist einen "Ausgabe Operator" für die Basisklasse als Funktion zu definieren, die dann einfach nur eine normale Memberfunktion aufruft.
    Diese Memberfunktion kann dann virtual sein, und in abgeleiteten Klassen überschrieben werden:

    #include <iostream>
    using namespace std;
    
    class menu
    {
    public:
        menu() { cout << "Konstruktor fuer abstrakte klasse" << endl; }
        virtual ~menu() { cout << "Destruktor fuer die abstrakte klasse " << endl; }
     
        virtual void anzeigen() = 0;
        virtual void ausgabe_in_stream(ostream& stream) const = 0;
     };
    
    ostream& operator << (ostream& stream, const menu& m)
    {
    	m.ausgabe_in_stream(stream);
    	return stream;
    }
    
    class start_menue : public menu
    {
    public:
    	virtual void anzeigen() { cout << "Start Menue" << endl; }
      
    	~start_menue() { cout << "Destruktor fuer Startmenü" << endl; }
    
    	virtual void ausgabe_in_stream(ostream& stream) const
    	{
    		cout << "cout << start_menue" << endl;
    	} 
    };
    
    class anderes_menue : public menu
    {
    public:
    	virtual void anzeigen() { cout << "Anderes Menue" << endl; }
      
    	~anderes_menue() { cout << "Destruktor fuer anderes Menü" << endl; }
    
    	virtual void ausgabe_in_stream(ostream& stream) const
    	{
    		cout << "cout << anderes_menue" << endl;
    	} 
    };
    
    int main()
    {
    	start_menue start;
     	cout << start;
    
    	anderes_menue a;
    	cout << a;
    
    	return 0;
    }
    

    Danke 🙂
    Wieder was neues gelernt ^^



  • virtual void ausgabe_in_stream(ostream& stream) const
    	{
    		stream << "cout << anderes_menue" << endl;
    	}
    

    An der Stelle stream , anstatt cout verwenden! Das kann sonst später ganz schön mächtig in die Hose gehen!



  • Richtig.

    Hatte ich Copy+Paste übernommen und erst später korrigiert. Nivea342 hat's leider zu schnell zitiert, da war mein EDIT noch nicht drinnen.


Anmelden zum Antworten