C++Talk.NET Forum Index C++Talk.NET
C++ language newsgroups
 
Archives   FAQFAQ   SearchSearch   MemberlistMemberlist   UsergroupsUsergroups   RegisterRegister 
 ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

Streams klonen

 
Post new topic   Reply to topic    C++Talk.NET Forum Index -> C++ (German)
View previous topic :: View next topic  
Author Message
Hendrik Belitz
Guest





PostPosted: Wed Jun 09, 2004 10:08 am    Post subject: Streams klonen Reply with quote



Hallo allerseits,

ich habe eine relativ mächtige Logging-Klasse in meiner Applikation, die
Ausgaben des log-streams auf den Bildschirm und/oder in eine Datei
schreibt. Nun möchte ich das ganze auch noch in ein GUI-Fenster klonen, dem
ich aber nur Strings übergeben kann. Meine Idee war also folgende:

Lege einen ostringstream an, der den streambuf des log streams verwendet:
os.rdbuf( log.rdbuf() );
und lese diesen regelmäßig aus.

Genau das funktioniert aber nicht, da ostringstream die rdbuf-Methoden
überdeckt (da er intern einen string_buf statt eines streambuf benutzt,
glaube ich).

Gibt es irgendeine Möglichkeit, trotzdem eine Umleitung zu implementieren,
ohne operator<< für alle Typen neu überladen zu müssen?

--
To get my real email adress, remove the two onkas
--
Hendrik Belitz
- Abort, Retry, Fthagn? -

--
de.comp.lang.iso-c++ - Moderation: mailto:voyager+mod (AT) bud (DOT) prima.de
FAQ: http://www.voyager.prima.de/cpp/ mailto:voyager+send-faq (AT) bud (DOT) prima.de
Back to top
Karl Heinz Buchegger
Guest





PostPosted: Wed Jun 09, 2004 10:19 am    Post subject: Re: Streams klonen Reply with quote



Hendrik Belitz wrote:
Quote:

Hallo allerseits,

ich habe eine relativ mächtige Logging-Klasse in meiner Applikation, die
Ausgaben des log-streams auf den Bildschirm und/oder in eine Datei
schreibt. Nun möchte ich das ganze auch noch in ein GUI-Fenster klonen, dem
ich aber nur Strings übergeben kann. Meine Idee war also folgende:

Lege einen ostringstream an, der den streambuf des log streams verwendet:
os.rdbuf( log.rdbuf() );
und lese diesen regelmäßig aus.

Genau das funktioniert aber nicht, da ostringstream die rdbuf-Methoden
überdeckt (da er intern einen string_buf statt eines streambuf benutzt,
glaube ich).

Gibt es irgendeine Möglichkeit, trotzdem eine Umleitung zu implementieren,
ohne operator<< für alle Typen neu überladen zu müssen?

Ich wuerds so machen:
Ich wuerde dem log-stream einen neuen streambuf unterjubelen.
Der neue streambuf macht folgendes: Leitet die Ausgabe an die
GUI weiter und ruft danach die Methode des alten streambuf
aus (damit Bildschirm und File wie gehabt funktionieren).

--
Karl Heinz Buchegger
[email]kbuchegg (AT) gascad (DOT) at[/email]

--
de.comp.lang.iso-c++ - Moderation: mailto:voyager+mod (AT) bud (DOT) prima.de
FAQ: http://www.voyager.prima.de/cpp/ mailto:voyager+send-faq (AT) bud (DOT) prima.de

Back to top
Markus Breuer
Guest





PostPosted: Wed Jun 09, 2004 5:16 pm    Post subject: Re: Streams klonen Reply with quote



Hendrik Belitz wrote:

Quote:
Hallo allerseits,

ich habe eine relativ mächtige Logging-Klasse in meiner Applikation, die
Ausgaben des log-streams auf den Bildschirm und/oder in eine Datei
schreibt. Nun möchte ich das ganze auch noch in ein GUI-Fenster klonen, dem
ich aber nur Strings übergeben kann. Meine Idee war also folgende:

Lege einen ostringstream an, der den streambuf des log streams verwendet:
os.rdbuf( log.rdbuf() );
und lese diesen regelmäßig aus.

Genau das funktioniert aber nicht, da ostringstream die rdbuf-Methoden
überdeckt (da er intern einen string_buf statt eines streambuf benutzt,
glaube ich).

Gibt es irgendeine Möglichkeit, trotzdem eine Umleitung zu implementieren,
ohne operator<< für alle Typen neu überladen zu müssen?

Mein Vorschlag ist das Interface der Logging-Klasse anzupassen. Ich gehe
davon aus, dass diese Klasse entsprechende Überladungen des << Operators
beinhaltet. Vermutlich verwendest du intern einen fstream oder einfach
cout. Ersetze den durch einen ostringstream. Jetzt musst du nur noch auf
std::endl reagieren, mit jedem endl entnimmst du per std() den gesamten
Inhalt und schriebst ihn weg.

Das Wegschreiben implementierst du, indem du einen Schnittstelle
definierst. Beispiel:

class LogIF {
public:
void write( const char* _data, int _size ) = 0;
};

und für die Konsole eine entsprechende Klasse implementierst:

class ConsoleLog : LogIF {
public:
void write( const char* _data, int _size )
{ cout.write( _data, _size ); }
};

Um nun mehrfache Ausgaben zu Loggen implementierst du wie folgt eine
weitere Klasse:

class DoubleLog : LogIF {
ConsoleLog con;
FileLog file;

public:
void write( const char* _data, int _size )
{ con.write( _data, _size ); file.write( _data, _size ); }
};

Hintergrund: zum Duplizieren musst du dich nicht mehr auf die Operatoren
<< konzentrieren, diese Arbeit wird einmal erledigt. Stattdessen
verwendest du das Ergebnis der Formatierungen und schreibst es en Block
in das Ziel. Dieser Weg ist viel einfacher, als die Implementierung
eines StreamBuf. Und da du dein eigenes Interface definiert hast, musst
du dich nicht mehr durch die Dokumentation der StreamBufs lesen.

Gruß Markus

--
de.comp.lang.iso-c++ - Moderation: mailto:voyager+mod (AT) bud (DOT) prima.de
FAQ: http://www.voyager.prima.de/cpp/ mailto:voyager+send-faq (AT) bud (DOT) prima.de

Back to top
Torsten Robitzki
Guest





PostPosted: Wed Jun 09, 2004 9:39 pm    Post subject: Re: Streams klonen Reply with quote

Markus Breuer wrote:
<snip>
Quote:
Dieser Weg ist viel einfacher, als die Implementierung
eines StreamBuf. Und da du dein eigenes Interface definiert hast, musst
du dich nicht mehr durch die Dokumentation der StreamBufs lesen.

Für einen einfachen stream buffer, muß man genau eine Funktion
(overflow()) implementieren, einfacher geht es eigentlich nicht. Die
Lösung, für das Umlenken von IO einen stream buffer zu verwenden, hat
den entscheidenen Vorteil, das Funktionen, die geschrieben wurden um
Daten auf einen std::ostream zu schreiben auch weiterhin funktionieren
und Funktionen nicht doppelt implementiert werden müssen.

mfg Torsten

--
de.comp.lang.iso-c++ - Moderation: mailto:voyager+mod (AT) bud (DOT) prima.de
FAQ: http://www.voyager.prima.de/cpp/ mailto:voyager+send-faq (AT) bud (DOT) prima.de

Back to top
Torsten Robitzki
Guest





PostPosted: Wed Jun 09, 2004 9:44 pm    Post subject: Re: Streams klonen Reply with quote

Hendrik Belitz wrote:

Quote:
Hallo allerseits,

ich habe eine relativ mächtige Logging-Klasse in meiner Applikation, die
Ausgaben des log-streams auf den Bildschirm und/oder in eine Datei
schreibt. Nun möchte ich das ganze auch noch in ein GUI-Fenster klonen, dem
ich aber nur Strings übergeben kann. Meine Idee war also folgende:

Lege einen ostringstream an, der den streambuf des log streams verwendet:
os.rdbuf( log.rdbuf() );
und lese diesen regelmäßig aus.

Genau das funktioniert aber nicht, da ostringstream die rdbuf-Methoden
überdeckt (da er intern einen string_buf statt eines streambuf benutzt,
glaube ich).

Gibt es irgendeine Möglichkeit, trotzdem eine Umleitung zu implementieren,
ohne operator<< für alle Typen neu überladen zu müssen?

Sieht mir so aus, als bräuchtest Du ein T-Stück. Sprich ein stream

buffer, der zwei stream buffer im c'tor referenziert und jeden output an
beide stream buffer weiter leitet.

mfg Torsten

--
de.comp.lang.iso-c++ - Moderation: mailto:voyager+mod (AT) bud (DOT) prima.de
FAQ: http://www.voyager.prima.de/cpp/ mailto:voyager+send-faq (AT) bud (DOT) prima.de

Back to top
kanze@gabi-soft.fr
Guest





PostPosted: Thu Jun 10, 2004 8:17 am    Post subject: Re: Streams klonen Reply with quote

Torsten Robitzki <firstname (AT) lastname (DOT) de> wrote

Quote:
Markus Breuer wrote:
snip
Dieser Weg ist viel einfacher, als die Implementierung eines
StreamBuf. Und da du dein eigenes Interface definiert hast, musst du
dich nicht mehr durch die Dokumentation der StreamBufs lesen.

Für einen einfachen stream buffer, muß man genau eine Funktion
(overflow()) implementieren,

Fast. Meistens braucht man auch einen Constructor:-).

Wenn mann irgendein Pufferisierung unterstutzt, dann soll man auch flush
unterstutzen. In seinem Fall denke ich, dass ich eigentlich
pufferisieren würde, und nur beim flush() an das GUI-Fenster übergeben.

Quote:
einfacher geht es eigentlich nicht. Die Lösung, für das Umlenken von
IO einen stream buffer zu verwenden, hat den entscheidenen Vorteil,
das Funktionen, die geschrieben wurden um Daten auf einen std::ostream
zu schreiben auch weiterhin funktionieren und Funktionen nicht doppelt
implementiert werden müssen.

Sicher. Anders ist es meistens interessanter, für Loggen einen anderen
Stromtyp zu benutzen, damit ich ein und ausschalten kann, und auch damit
ich die benötigen Flush zwingen kann. Freilich aber enthält dieser
Stromtyp einen richtigen ostream, dass sein templatierter operator<<
benutzt:

template< typename T >
LogStream&
LogStream::operator<<( T const& value )
{
if ( myIsActive ) {
*myStream << value ;
}
return *this ;
}

Dieser ostream enthält normalerweise einen filtrierenden Streambuf, der
einen Zeitstempel u.s.w. am Zeilenanfang zufügt, und dann verteilt an
die eigene Streambuf.

--
James Kanze GABI Software
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34

--
de.comp.lang.iso-c++ - Moderation: mailto:voyager+mod (AT) bud (DOT) prima.de
FAQ: http://www.voyager.prima.de/cpp/ mailto:voyager+send-faq (AT) bud (DOT) prima.de

Back to top
Torsten Robitzki
Guest





PostPosted: Thu Jun 10, 2004 6:25 pm    Post subject: Re: Streams klonen Reply with quote

[email]kanze (AT) gabi-soft (DOT) fr[/email] wrote:
<snip>
Quote:
Für einen einfachen stream buffer, muß man genau eine Funktion
(overflow()) implementieren,


Fast. Meistens braucht man auch einen Constructor:-).

Wenn mann irgendein Pufferisierung unterstutzt, dann soll man auch flush
unterstutzen. In seinem Fall denke ich, dass ich eigentlich
pufferisieren würde, und nur beim flush() an das GUI-Fenster übergeben.


Ist selbst mit Pufferung aber immer noch nicht besonders kompliziert
(wenn man sich erst einmal an die kryptischen Funktionsnamen gewöhnt hat).

Quote:
einfacher geht es eigentlich nicht. Die Lösung, für das Umlenken von
IO einen stream buffer zu verwenden, hat den entscheidenen Vorteil,
das Funktionen, die geschrieben wurden um Daten auf einen std::ostream
zu schreiben auch weiterhin funktionieren und Funktionen nicht doppelt
implementiert werden müssen.


Sicher. Anders ist es meistens interessanter, für Loggen einen anderen
Stromtyp zu benutzen, damit ich ein und ausschalten kann, und auch damit
ich die benötigen Flush zwingen kann. Freilich aber enthält dieser
Stromtyp einen richtigen ostream, dass sein templatierter operator
benutzt:

template< typename T
LogStream&
LogStream::operator<<( T const& value )
{
if ( myIsActive ) {
*myStream << value ;
}
return *this ;
}

Dieser ostream enthält normalerweise einen filtrierenden Streambuf, der
einen Zeitstempel u.s.w. am Zeilenanfang zufügt, und dann verteilt an
die eigene Streambuf.

Sieht auch schön aus. Für den Fall, das eine Funktion zum textuellen
Ausgeben nun aber nicht operator<<() heißt bzw. eine Funktion zum
Beispiel zum Protokollieren einen zusätzlichen Parameter vom Typen
std::ostream nimmt, müßte man den LogStream in einen std::ostream&
konvertieren (was natürlich möglich ist) und nimmt ihm damit die
Möglichkeit den Datenstrom in irgend einer Weise zu kontrollieren.

Mir ist auch nicht ganz klar, wie Du bei dieser Lösung Zeilenumbrüche
erkennst. operator<<(std::ostream&, const T&) könnte ja im obigen
Beispiel beliebig viele Zeilenumbrüche einfügen.

Die Lösung hat aber ganz klar den Vorteil, das nicht erst Formatiert
wird um dann später fest zu stellen, das das ganze gar nicht ausgegeben
werden soll.

Das mit dem Filtern kann meine stream buffer Lösung auch, in dem stream
Manipulatoren über dynamic_cast prüfen, ob der stream buffer ein
trace_stream_buf ist, und wenn es der Fall, den Filter dem entsprechend
anpassen.

trace << trace_main << "Hallo Welt" << std::endl;

"Hallo Welt" würde ausgegeben werden, wenn trace.rdbuf() keinen
trace_stream_buf* zurückliefert oder aber wenn das der Fall ist, der
stream buffer so eingestellt ist, das Ausgaben mit dem level main
ausgegeben werden sollen.

Leider funktiert das ganze dann auch nur noch, wenn da nicht noch andere
stream buffer zwischen geschaltet sind, wie ein T-Stück aus meinem
anderen posting zum Thema.

mfg Torsten

--
de.comp.lang.iso-c++ - Moderation: mailto:voyager+mod (AT) bud (DOT) prima.de
FAQ: http://www.voyager.prima.de/cpp/ mailto:voyager+send-faq (AT) bud (DOT) prima.de

Back to top
kanze@gabi-soft.fr
Guest





PostPosted: Fri Jun 11, 2004 9:02 am    Post subject: Re: Streams klonen Reply with quote

Torsten Robitzki <firstname (AT) lastname (DOT) de> wrote

Quote:
kanze (AT) gabi-soft (DOT) fr wrote:
snip
Für einen einfachen stream buffer, muß man genau eine Funktion
(overflow()) implementieren,

Fast. Meistens braucht man auch einen Constructor:-).

Wenn mann irgendein Pufferisierung unterstutzt, dann soll man auch
flush unterstutzen. In seinem Fall denke ich, dass ich eigentlich
pufferisieren würde, und nur beim flush() an das GUI-Fenster
übergeben.

Ist selbst mit Pufferung aber immer noch nicht besonders kompliziert
(wenn man sich erst einmal an die kryptischen Funktionsnamen gewöhnt
hat).

Habe es auch nicht gesagt, dass es kompliziert ist:-).

In der Tat habe ich eine Menge von vorhandenen streambuf's auf meinem
Site ([url]www.gabi-soft.fr)[/url]. Für viele Sachen kann ich darauf basieren, und
häufig dann mit 5 oder 6 Zeilen neuen Code herauskomment.

Quote:
einfacher geht es eigentlich nicht. Die Lösung, für das Umlenken von
IO einen stream buffer zu verwenden, hat den entscheidenen Vorteil,
das Funktionen, die geschrieben wurden um Daten auf einen
std::ostream zu schreiben auch weiterhin funktionieren und
Funktionen nicht doppelt implementiert werden müssen.

Sicher. Anders ist es meistens interessanter, für Loggen einen
anderen Stromtyp zu benutzen, damit ich ein und ausschalten kann,
und auch damit ich die benötigen Flush zwingen kann. Freilich aber
enthält dieser Stromtyp einen richtigen ostream, dass sein
templatierter operator<< benutzt:

template< typename T
LogStream&
LogStream::operator<<( T const& value )
{
if ( myIsActive ) {
*myStream << value ;
}
return *this ;
}

Dieser ostream enthält normalerweise einen filtrierenden Streambuf,
der einen Zeitstempel u.s.w. am Zeilenanfang zufügt, und dann
verteilt an die eigene Streambuf.

Sieht auch schön aus. Für den Fall, das eine Funktion zum textuellen
Ausgeben nun aber nicht operator<<() heißt bzw. eine Funktion zum
Beispiel zum Protokollieren einen zusätzlichen Parameter vom Typen
std::ostream nimmt, müßte man den LogStream in einen std::ostream&
konvertieren (was natürlich möglich ist) und nimmt ihm damit die
Möglichkeit den Datenstrom in irgend einer Weise zu kontrollieren.

Ja und nein. Falls ein Typ nicht den operator<< unterstutzt, aber hat
andere Funktionen zur Ausgabe, kann ich immer einen auf den anderen
Funktionen basierten operator<< selber schreiben.

Aber der normalle Idiom in C++ *ist* operator<<.

Quote:
Mir ist auch nicht ganz klar, wie Du bei dieser Lösung Zeilenumbrüche
erkennst. operator<<(std::ostream&, const T&) könnte ja im obigen
Beispiel beliebig viele Zeilenumbrüche einfügen.

Mit einem sonderen streambuf:-). Eine Lösung schliesst die andere nicht
aus.

Quote:
Die Lösung hat aber ganz klar den Vorteil, das nicht erst Formatiert
wird um dann später fest zu stellen, das das ganze gar nicht
ausgegeben werden soll.

Und die Formattierung kann teuer sein. Erfahrungsgemäß soll die
ausgeschaltete Logging möglichst wenig kosten. Amsonst lässt man es
nicht im gelieferten Code. D.h., dass gerade dann, wenn du es meist
brauchst, steht es nicht zur Verfügung.

Quote:
Das mit dem Filtern kann meine stream buffer Lösung auch, in dem
stream Manipulatoren über dynamic_cast prüfen, ob der stream buffer
ein trace_stream_buf ist, und wenn es der Fall, den Filter dem
entsprechend anpassen.

trace << trace_main << "Hallo Welt" << std::endl;

Meistens bei mir sieht es so ähnlich aus:

Log::logger( severity ) << "Meldung" ;

Das Log Subsystem richtet alle der betroffenen Streams ein. Also weiß er
wohl, was er für einen streambuf hat. In der Tat, enthält er sogar einen
Zeiger darauf. Mit dem richtigen Typ, damit keine Typumwandlung nötig
ist.

Quote:
"Hallo Welt" würde ausgegeben werden, wenn trace.rdbuf() keinen
trace_stream_buf* zurückliefert oder aber wenn das der Fall ist, der
stream buffer so eingestellt ist, das Ausgaben mit dem level main
ausgegeben werden sollen.

Leider funktiert das ganze dann auch nur noch, wenn da nicht noch
andere stream buffer zwischen geschaltet sind, wie ein T-Stück aus
meinem anderen posting zum Thema.

Du musst sie in der richtigen Reihenfolge einschalten. Der log_streambuf
leitet weiter auf einen T_streambuf, und nicht umgekehrt.

In der Tat habe ich "EventGeneratingOutputStreambuf" und
"OutputStreamWrapper" für die erste Schichte ; typischerweise,
"EventGeneratingOutputStreambuf" leitet auf eine Konfigurierung
abhängige verteilende streambuf, der eine std::vector< streambuf* >
enthält, und weiter leitet.

--
James Kanze GABI Software
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34

--
de.comp.lang.iso-c++ - Moderation: mailto:voyager+mod (AT) bud (DOT) prima.de
FAQ: http://www.voyager.prima.de/cpp/ mailto:voyager+send-faq (AT) bud (DOT) prima.de

Back to top
Display posts from previous:   
Post new topic   Reply to topic    C++Talk.NET Forum Index -> C++ (German) All times are GMT
Page 1 of 1

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2001, 2006 phpBB Group
SEO toolkit © 2004-2006 webmedic.