Klasse für Ausgabe ableiten ?



  • Tach!

    Ich programmiere einen µC in C++, Ausgaben auf der Konsole werden wie üblich mit cout gehandhabt. Zusätzlich habe ich noch ein LC-Display angeschlossen. Nun würde ich mir gerne eine Klasse deklarieren (olcdstream), und davon ein Objekt bilden (lcdout), so dass ich z.B. mit

    lcdout << "Hallo" << i << endl;

    auf dem Display schreiben kann.

    Das müsste doch eigentlich relativ einfach möglich sein, indem ich in meiner Klasse die Methode (welche?) überschreibe welche für die eigentliche Ausgabe verantwortlich ist. Allerdings blicke ich in dem Jungel aus ios, ostream, streambase, etc. überhaupt noch nicht durch.

    Hätte da jemand einen Tip für mich ?

    Grüße
    Stefan



  • ostream &  operator<< (ostream &stream, const DeineKlasse & d){
        stream<<d.DeineWerte1<<" ";
        stream<< td.DeineWere2<<" ";
        return stream;
    }
    

    global definieren und mit deiner klasse befreunden.

    class DeineKlasse{
    
    //....
       friend ostream &  operator<< (ostream &stream, const DeineKlasse & d);
    
    };
    


  • @elise: Ich glaube, Phun meinte das andere Ende der Ausgaben 😉

    Dazu leitest du dir am besten eine eigene Pufferklasse von std::streambuf (bzw. std::basic_streambuf<...>) ab und überschreibst die Methode overflow(), mit der du dein LCD-Display ansteuerst. Anschließend definierst du dir eine eigene Streamklasse, die diesen Puffer verwendet:

    class lcdbuf : public std::streambuf
    {
      virtual int_type overflow(int_type c)
      {
        //gibt Zeichen c aus
        //Rückgabe: c oder EOF
      }
    }
    
    class olcdstream : public std::ostream
    {
      lcdbuf buffer;
    public:
      olcdstream() : std::ostream(&buf) {}
    };
    

    (mehr zur Arbeit mit Streams gibt's demnächst im Magazin)



  • CStoll schrieb:

    @elise: Ich glaube, Phun meinte das andere Ende der Ausgaben 😉

    jep, habe verkehrtrum gedacht. kein wunder, so früh am morgen... 🙂



  • Super!

    Gerade getestet, funktioniert hervorragend, herzlichen Dank.
    Nun muss ich mich da noch durcharbeiten, ich möchte das ganze natürlich auch verstehen.
    Ich möchte noch Manipulatoren (ich glaub so hieß das) einbauen, damit ich das Display a) löschen kann und b) explizit in eine bestimmte Zeile springen kann.
    Was kommt eigentlich, so wie es im Moment ist, bei meiner Overflow-Methode an, wenn ich ein <<endl an den olcdstream gebe ?

    Gruß
    Stefan



  • Phunkafizer schrieb:

    Ich möchte noch Manipulatoren (ich glaub so hieß das) einbauen, damit ich das Display a) löschen kann und b) explizit in eine bestimmte Zeile springen kann.

    Einfache Manipulatoren kannst du als Stream-Funktion definieren, für das gotoxy wäre es etwas komplizierter:

    olcdstream& clear(olcdstream& strm)
    {
      //Display löschen
      return strm;
    }
    //-> Anwendung
    olcdstream display;
    ...
    display<<clear;
    //ich hoffe zumindest, daß es geht - notfalls arbeitet clear auf ostream&'s und überprüft selber, ob es den richtigen Typ bekommen hat
    
    class gotoxy
    {
      int x,y;
    public:
      gotoxy(int nx,int ny) : x(nx,y(ny) {}
      friend olcdstream& operator<<(olcdstream& strm,const gotoxy& target)
      {
        //springe auf Zielposition
        return strm;
      }
    };
    ...
    display<<gotoxy(1,1);
    

    Was kommt eigentlich, so wie es im Moment ist, bei meiner Overflow-Methode an, wenn ich ein <<endl an den olcdstream gebe ?

    Afaik kommt dort ein \n an und anschließend ein flush()-Befehl (der aber nichts macht, weil die Klasse keinen internen Puffer verwendet).



  • Habe zunächst die clear Funktion implementiert, selbige wird aber leider nicht aufgerufen wenn ich

    diplay << clear;

    schreibe.

    Wenn ich die Klasse gotoxy mit rein mache will mein Compiler nicht mehr kompilieren. Sollte ich mich wohl zunächst mal einlesen wie das mit dem "friend" Operator funktioniert, da steig ich noch nicht durch wozu der gut ist. OOP in C++ ist offensichtlich noch weitaus komplexer als in Delphi, da steige ich ganz gut durch.

    Habs noch kurz anders versucht, und zwar habe ich in die Klasse olcdstream eine Methode implementiert:

    class olcdstream: public std::ostream
    {
    lcdbuf buffer;
    public:
    olcdstream(): std::ostream(&buffer) {}
    void clrscr();
    };

    void olcdstream::clrscr()
    {
    cout << "CLEAR!";
    }

    Aber die Methode wird irgendwie mit display.clrscr() nicht aufgerufen.
    Hm, da gibt's noch einiges zu lernen...

    Gruß
    Stefan



  • Phunkafizer schrieb:

    Wenn ich die Klasse gotoxy mit rein mache will mein Compiler nicht mehr kompilieren.

    Was sagt er denn? (die obige Klasse habe ich auf die Schnelle geschrieben, ist also ungetestet)

    Sollte ich mich wohl zunächst mal einlesen wie das mit dem "friend" Operator funktioniert, da steig ich noch nicht durch wozu der gut ist. OOP in C++ ist offensichtlich noch weitaus komplexer als in Delphi, da steige ich ganz gut durch.

    "friend" definiert einen Freund der Klasse, d.h. eine externe Funktion oder andere Klasse bekommt die Erlaubnis, auf deine privaten Elemente zugreifen zu dürfen.

    Habs noch kurz anders versucht, und zwar habe ich in die Klasse olcdstream eine Methode implementiert:

    class olcdstream: public std::ostream
    {
      lcdbuf buffer;
      public:
        olcdstream(): std::ostream(&buffer) {}
        void clrscr();
    };
    
    void olcdstream::clrscr()
    {
      cout << "CLEAR!";
    }
    

    Aber die Methode wird irgendwie mit display.clrscr() nicht aufgerufen.
    Hm, da gibt's noch einiges zu lernen...

    Eigentlich sollte sie aber (zumindest solange display ein olcdstream ist).



  • Nachtrag:

    Letzten Teil ignorieren, das

    void olcdstream::clrscr()

    funktioniert wunderbar...



  • Deinem Clear-Manipulator kann man evtl. durch ne Template-Funktion auf die Sprünge helfen:

    // Der Manipulator von CStoll unter Verwendung von clrscr
    olcdstream& clear(olcdstream& strm)
    {
      strm.clrscr();
      return strm;
    }
    
    // Das Template
    template<typename Func>
    olcdstream& operator<<(olcdstream& strm, Func fn)
    {
      return fn(strm);
    }
    


  • @CStoll:

    gotoxy(int nx,int ny) : x(nx,y(ny) {}
    

    Diese Zeile mag er nicht, dass da ein Fehler drin ist sehe ich, aber ich weiß nicht wie selbige richtig heißen müsste 😕

    Diese Methode stellt ja den Konstruktor da, nach dem Doppelpunkt wird ja normalerweise der geerbte Konstruktor aufgerufen, aber gotoxy hat ja keinen Konstruktor geerbt bekommen ?

    Stefan



  • gotoxy (int nx, int ny) : x (nx), y (ny) {}
    

    Mit der Konstruktorliste kann man auch Member initialisieren (und zwar mit deren Konstruktor).


Anmelden zum Antworten