Forum: Mikrocontroller und Digitale Elektronik C++ LCD stream Klasse


von Stefan (Gast)


Lesenswert?

Hallo,

ich habe mir eine Klasse für ein Display geschrieben:
1
class Lcdbasestream: public streambuf, public ostream
2
{
3
  private:
4
    int overflow(int = EOF);
5
                int linelength;
6
  public:
7
     Lcdbasestream(int boardversion);
8
      ~Lcdbasestream(void);
9
      void Clear();
10
      virtual void Gotoxy(int x, int y) = 0;
11
    void setLight(bool state);
12
};
13
14
extern Lcdbasestream lcd;

So kann ich ganz bequem mit lcd << "Test" etwas auf mein Display 
schreiben. Drei Fragen:

1. Wie kann muss ich den Code erweitern, so dass ich die Clear Methode 
in der Art "cout << clr << i" aufrufen kann?
2. Gleiches wie oben für die Goto Methode, also mit Parametern, so dass 
ich etwa "lcd << goto(10, 2) << i" verwenden kann?
3. Wie kann ich mir einen Manipulator schreiben, der mir die nächste 
Ausgabe zentriert, also z.B. lcd << center << "Test"? Die Zeilenlänge 
liegt als Attribut in der LCD Klasse vor.

Grüße
Stefan

von Bastler (Gast)


Lesenswert?

Einfach mal C++ streams Doku anschauen, da findet man "custom 
manipulators". Und Vorsicht: Auf LCD streamen klingt nach μC. Da kommt 
gleich der dicke Fisch mit "ASM ist besser" um die Ecke.

von rmu (Gast)


Lesenswert?


von Torsten R. (Firma: Torrox.de) (torstenrobitzki)


Lesenswert?

Hallo Stefan,

0) Deine Klasse sollte nicht public von stream und buffer erben. Da 
das Verhalten von streams in der Regel über ihre buffer implementiert 
werden, würde ich einen buffer implementieren und dann für convenience 
einen stream, der einen buffer enthält und diesen als c'tor argument an 
den stream weiter reicht.

für 1-3) müsstest Du dann erkennen, ob der stream buffer eines streams 
deinem buffer typen entspricht. Hier würde ich dynamic_cast verwenden 
(wenn bei Dir verfügbar) (ansonsten wären xalloc()/iword und static_cast 
Dein Freund).

1) Manipulatoren, die keine zusätzlichen Argumente nehmen (z.B. endl) 
sind Funktionen, die einen ostream als argument nehmen und einen ostream 
zurück geben:
1
std::ostream& clr( std::ostream& out ) {
2
    lcd_buffer* const buf = dynamic_cast< lcd_buffer* >( out.rdbuf() );
3
4
    if ( buf )
5
        buf->Clear();
6
7
    return out;
8
}

2) Manipulatoren, die Argumente nehmen lassen sich gut als Typen mit 
Konstruktoren implementieren:
1
struct goto
2
{
3
    goto( int ax, int ay )
4
        : x( ax )
5
        , y( ay )
6
    {}
7
8
    int x, y;
9
};
10
11
std::ostream& operator<<( std::ostream& out, const goto& target )
12
{
13
    lcd_buffer* const buf = dynamic_cast< lcd_buffer* >( out.rdbuf() );
14
15
    if ( buf )
16
        buf->goto_xy( target.x, target.y );
17
18
    return out;    
19
}

3) Da müsstest Du dir merken, dass die nächste Zeile zentriert werden 
soll (siehe 1) und dann jedes Zeichen, dass im stream buffer vorbei 
kommt zwischen speichern und darauf untersuchen, ob es ein Zeilenumbruch 
ist. Das kann man aber auch optimieren, wenn man eine ganze Kette an 
Zeichen bekommt, kann man natürlich diese komplett untersuchen.

HTH
Torsten

von Stefan (Gast)


Lesenswert?

>Da kommt gleich der dicke Fisch mit "ASM ist besser" um die Ecke.
Yo Danke für den Hinweis, habe schon gesehen dass dieses Thema hier im 
Forum etwas "nötiger als nötig" diskutiert wird, deswegen werde ich hier 
nicht schreiben für welche Plattform das ganze ist :-)

Danke Torsten, auch für den Tip 0. Einen dynamic_cast habe ich nicht, 
aber ich habe es mit einem static_cast gemacht. Gibt letzterer auch 0 
zurück wenn ein casten nicht möglich ist?

Stefan

von Torsten R. (Firma: Torrox.de) (torstenrobitzki)


Lesenswert?

Stefan schrieb:

> Danke Torsten, auch für den Tip 0. Einen dynamic_cast habe ich nicht,
> aber ich habe es mit einem static_cast gemacht. Gibt letzterer auch 0
> zurück wenn ein casten nicht möglich ist?

Nein, der liefert dann nur "undefined behaviour", das wird nicht 
funktionieren, es sei den Du kannst sicherstellen, dass jeder Stream 
(inkl. string streams etc.) nur lcd_buffer enthält. Ansonsten brauchst 
zwingend eine Möglichkeit, zur Laufzeit zu unterscheiden, ob es ein 
lcd_buffer ist. Dazu fallen mir zwei Möglichkeiten ein:

1) Jeder stream enthält ein array. Mit std::ios_base::xalloc() kannst Du 
Dir einen slot/index in jedes array aller streams reservieren ...

2) zweite Möglichkeit wäre, in den Konstruktoren und Destruktor des 
lcd_buffer eine intrinsisch, verkettet Liste (jeder lcd_buffer enthält 
noch mal zusätzlich einen Zeiger auf den nächsten) zu führen, über die 
Du nachschlagen kannst, ob es ein stream buffer ein lcd_buffer ist oder 
nicht.

oder
3) Du verzichtest auf die std-streams, orientierst Dich an deren Syntax 
und baust das ganze parallel selbst auf.

von Zelebralus (Gast)


Lesenswert?

"Der dicke Fisch" ist doch ein Säuger!?

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.