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 

Sorgenkind ostream

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





PostPosted: Mon Oct 04, 2004 2:54 pm    Post subject: Sorgenkind ostream Reply with quote




Hallo,

folgendes Problem beschäftigt mich als relativer C++ Neuling jetzt schon
eine ganze Weile und ich habe langsam das Gefühl, dass ich es
konzeptionell falsch angegangen bin.

Ich möchte gleichzeitig in mehrere Streams schreiben, z.B. in die
Standardausgabe und in ein Textfile. Dazu habe ich ein Target-objekt
entworfen, das eine Ausgabemethode und die Information bereitstellt in
welchen Stream geschrieben werden soll.

also verkürzt so ungefähr:

class Target{
private:
ostream outStream;
public:
Target( ostream & os );
Target( const string & pathToFile )
void output( string s );
};

Natürlich tut das noch etwas mehr, z.B. Filtern welche Ausgaben
geschrieben werden sollen und welche nicht.

Der ersten Konstruktor holt sich aus os den streambuffer und
initialisert damit den outStream. Der zweite öffnet einen FileBuf und
initialsisiert dann mit diesem den outStream. Ich hätte gerne sowas wie

tg1 = new Target("test.txt");
tg2 = new Target(cout);

gehabt.

Leider meckert der compiler in den Konstruktoren, weil er wohl
vergeblich nach dem Standard-ctor von ostream sucht.

Dann hab ich gedacht versuchs mal mit einem Pointer auf den outStream
und erzeuge das Object erst mit new in den Konstruktoren. Aber dann
bekomme ich einen Speicherzugriffsfehler wenn ich schreiben will:

(* outStream) << s << endl;

Was mache ich falsch oder ist das kompletter Mist?

vielen Dank
Harris

--
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
Chris Theis
Guest





PostPosted: Mon Oct 04, 2004 3:57 pm    Post subject: Re: Sorgenkind ostream Reply with quote




"harrisx" <harrisx (AT) gmx (DOT) de> wrote

Quote:

Hallo,

folgendes Problem beschäftigt mich als relativer C++ Neuling jetzt schon
eine ganze Weile und ich habe langsam das Gefühl, dass ich es
konzeptionell falsch angegangen bin.

Ich möchte gleichzeitig in mehrere Streams schreiben, z.B. in die
Standardausgabe und in ein Textfile. Dazu habe ich ein Target-objekt
entworfen, das eine Ausgabemethode und die Information bereitstellt in
welchen Stream geschrieben werden soll.

also verkürzt so ungefähr:

class Target{
private:
ostream outStream;
public:
Target( ostream & os );
Target( const string & pathToFile )
void output( string s );
};

Natürlich tut das noch etwas mehr, z.B. Filtern welche Ausgaben
geschrieben werden sollen und welche nicht.

Der ersten Konstruktor holt sich aus os den streambuffer und
initialisert damit den outStream. Der zweite öffnet einen FileBuf und
initialsisiert dann mit diesem den outStream. Ich hätte gerne sowas wie

tg1 = new Target("test.txt");
tg2 = new Target(cout);

gehabt.

Leider meckert der compiler in den Konstruktoren, weil er wohl
vergeblich nach dem Standard-ctor von ostream sucht.

Das Kopieren von streams soll auch nicht funktionieren ;-)

Quote:

Dann hab ich gedacht versuchs mal mit einem Pointer auf den outStream
und erzeuge das Object erst mit new in den Konstruktoren. Aber dann
bekomme ich einen Speicherzugriffsfehler wenn ich schreiben will:

Diese Idee sollte prinzipiell funktionieren. Ich wuerde folgendes Konzept

nehmen, welches zusaetzlich per bool-Flag noch darueber Buch fuehrt ob der
Stream von Target auch geloescht werden soll um dangling pointers zu
vermeiden. Dies ist bei selbst erstellten Stream Objekten natuerlich
notwendig, jedoch nicht bei globalen Streams wie z.B. cout, cerr usw.

class Target{
private:
ostream* outStream;
bool bMustDestroy;

public:
Target( ostream& os ) : outStream(&os), bMustDestroy(false) {}
Target( const string & pathToFile ) : outStream( new
ofstream(pathToFile.c_str() ) ), bMustDestroy(true) {}
~Target() {
if( bMustDestroy )
delete outStream;
}

operator bool() const { // test if opening of the stream succeeded
return *outStream;
}

ostream& output( const string& Msg ) { return *outStream << Msg; }
};

ostream& operator<<( Target& rhs, const string& Msg )
{
return rhs.output(Msg) ;
}

int main ()
{
Target Console( cout );
Target File("test.txt");

if( Console)
cout << "Console opening successful" << endl;

Console << "Yeeeha" << std::endl;
File << "Yeeeha" << std::endl;
return (0);
}

mfG
Chris

--
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
Thomas Maeder
Guest





PostPosted: Mon Oct 04, 2004 4:33 pm    Post subject: Re: Sorgenkind ostream Reply with quote



harrisx <harrisx (AT) gmx (DOT) de> writes:

Quote:
Ich möchte gleichzeitig in mehrere Streams schreiben, z.B. in die
Standardausgabe und in ein Textfile.

Das ist schon ein Widerspruch.

Vermutlich willst Du an zwei Orte gleichzeitig schreiben; dazu brauchst Du
aber nicht zwei Streams.

In der C++-iostream-Bibliothek unterscheidet man
- streams und
- streambufs

Die streams sorgen für die Formatierung der geschriebenen Objekte, die
streambufs dafür, dass die formatierte Bytefolge der geschriebenen Objekte
am richtigen Ort (Datei, Konsole, std::string, usw.) landet.


Was Du also brauchst, ist eine Klasse, deren Instanzen so tun, als wären
sie streambuf-Objekte, die aber in Tat und Wahrheit die formatierte
Bytefolge an zwei streambuf-Objekte weiterleitet.

Etwa:

#include <fstream>
#include <iostream>
#include <ostream>

class Weiche : public std::streambuf
{
public:
Weiche(std::streambuf &s1, std::streambuf &s2)
: forward1(s1)
, forward2(s2)
{
}

virtual int_type overflow(int_type i)
{
int_type const result(forward1.sputc(i));
if (result!=traits_type::eof())
forward2.sputc(i);
return result;
}

private:
std::streambuf &forward1;
std::streambuf &forward2;
};

int main()
{
std::filebuf fb;
if (fb.open("dateiname", std::ios_base::out | std::ios_base::trunc))
{
Weiche w(fb,*std::cout.rdbuf());
std::ostream o(&w);
if (o << 10 << std::endl && fb.close())
std::cout << "okn";
}
}

Weiche hat selber keinen Puffer; jedes Zeichen erzeugt also einen Überlauf
und damit den Aufruf der Memberfunktion overflow(). Diese schickt das
Zeichen an die beiden Ausgänge weiter.

Wie die Logik in Weiche::overflow() genau aussehen muss, wirst Du selbst
entscheiden müssen, je nachdem, was zu tun ist, wenn die erste Delegation
misslingt.

Damit die Klasse wirklich nützlich ist, kannst Du Dir überlegen, sie zum
Template zu machen (à la std::basic_streambuf).

--
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: Mon Oct 04, 2004 5:27 pm    Post subject: Re: Sorgenkind ostream Reply with quote

harrisx wrote:

Quote:
class Target{
private:
ostream outStream;
public:
Target( ostream & os );
Target( const string & pathToFile )
void output( string s );
};

[...]

Der ersten Konstruktor holt sich aus os den streambuffer und
initialisert damit den outStream. Der zweite öffnet einen FileBuf und
initialsisiert dann mit diesem den outStream. Ich hätte gerne sowas wie

tg1 = new Target("test.txt");
tg2 = new Target(cout);

gehabt.

Leider meckert der compiler in den Konstruktoren, weil er wohl
vergeblich nach dem Standard-ctor von ostream sucht.

Du hast konzeptionell etwas wesentliches nicht verstanden: bei
std::ostream handelt es sich um ein Interface oder eine Schittstelle.
Ein Interface definiert Methoden zum Zugriff, definiert also eine
Konvention. Für deine Arbeit benötigst du nun aber eine Klasse, die
diese Schnittstelle implementiert. Da gibt es beispielsweise die
Variable std::cout hinter der ein Objekt steckt, welches das Interface
von std::ostream implementiert. Um welchen Typ es sich konkret handelt,
spielt für dich keine Rolle. Du bist mit dem Wissen ausgestattet, dass
das Objekt die Schnittstelle std::ostream implementiert, d.h. die kannst
die Methoden von std:ostream aufrufen.
Ähnlich sieht das beim Objekt std::ostringstream aus: diese Klasse
implementiert auch das Interface von std::ostream, du kannst die von
ostream bekannten Methoden auch für diese Klasse verwenden. Vorteil: du
eigenest dir die Eigenschaften dieser Schnittstelle einmal an und kannst
sie bei zwei Klassen unterschiedlichen Typs anwenden.
Beim std::ofstream sieht das ähnlich aus.

Quote:
Dann hab ich gedacht versuchs mal mit einem Pointer auf den outStream
und erzeuge das Object erst mit new in den Konstruktoren. Aber dann
bekomme ich einen Speicherzugriffsfehler wenn ich schreiben will:

(* outStream) << s << endl;

Was mache ich falsch oder ist das kompletter Mist?

Arbeite mit der Schnittstelle:

class Foo {
....
public:
void schreibe_mich_in( std::ostream& _einen_ostream )
{
_einen_ostream << "Ich bin die Klasse Foo."M
}
};

Und nun verwende die Schnittstelle! Auf die Console schreiben?

class Foo einFoo;

einFoo.schreibe_mich_in( std::cout );

In eine Datei? Dann

std::ofstream eine_datei( "c:\ausgabe.txt" );

einFoo.schreibe_mich_in( eine_datei );

In einen std::string? Dann

std::ostringstream einen_stringstream;

einFoo.schreibe_mich_in( einen_stringstream );

std::string die_zeichenkette( einen_stringstream.str() );

Voila!

Da die Klasse std::ostream nur eine Schnittstelle ist, kannst du auch
nicht direkt ein Objekt dieses Typs instanzieren. Dein Compiler meckert
zu recht. Ein alleinstehenden ostream Objekt macht demnach auch keinen
Sinn, ein ostream kann somit also nur Bestandteil einer umfassenden
Klasse sein: ostringstream oder ofstream.

Alles klar?

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: Mon Oct 04, 2004 5:57 pm    Post subject: Re: Sorgenkind ostream Reply with quote

Markus Breuer wrote:
<snip>
Quote:
Da die Klasse std::ostream nur eine Schnittstelle ist, kannst du auch
nicht direkt ein Objekt dieses Typs instanzieren. Dein Compiler meckert
zu recht. Ein alleinstehenden ostream Objekt macht demnach auch keinen
Sinn, ein ostream kann somit also nur Bestandteil einer umfassenden
Klasse sein: ostringstream oder ofstream.

Man kann einen std::ostream durch aus mit einem geeigneten Streambuffer
instanziieren.

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
Markus Breuer
Guest





PostPosted: Mon Oct 04, 2004 7:24 pm    Post subject: Re: Sorgenkind ostream Reply with quote

Torsten Robitzki wrote:
Quote:
Markus Breuer wrote:
snip

Da die Klasse std::ostream nur eine Schnittstelle ist, kannst du auch
nicht direkt ein Objekt dieses Typs instanzieren. Dein Compiler
meckert zu recht. Ein alleinstehenden ostream Objekt macht demnach
auch keinen Sinn, ein ostream kann somit also nur Bestandteil einer
umfassenden Klasse sein: ostringstream oder ofstream.


Man kann einen std::ostream durch aus mit einem geeigneten Streambuffer
instanziieren.

Stimmt! Dieser Mechanismus ist aber für eine eigene
Stream-Implementierung angedacht. Für Spielereien mit Stream scheint mir
das nicht der richtige Weg und einem Anfänger (mit dem haben wir es hier
zu tun) würde ich erst gar nicht auf solche Ideen bringen. Surprised)

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
kanze@gabi-soft.fr
Guest





PostPosted: Tue Oct 05, 2004 9:54 am    Post subject: Re: Sorgenkind ostream Reply with quote

Markus Breuer <markus.breuer (AT) gmx (DOT) de> wrote

Quote:
Torsten Robitzki wrote:
Markus Breuer wrote:
snip

Da die Klasse std::ostream nur eine Schnittstelle ist, kannst du
auch nicht direkt ein Objekt dieses Typs instanzieren. Dein
Compiler meckert zu recht. Ein alleinstehenden ostream Objekt macht
demnach auch keinen Sinn, ein ostream kann somit also nur
Bestandteil einer umfassenden Klasse sein: ostringstream oder
ofstream.

Man kann einen std::ostream durch aus mit einem geeigneten
Streambuffer instanziieren.

Stimmt! Dieser Mechanismus ist aber für eine eigene
Stream-Implementierung angedacht.

Nicht nur. Es kommt mir vor, auch istream direkt zu benutzen.

Quote:
Für Spielereien mit Stream scheint mir das nicht der richtige Weg und
einem Anfänger (mit dem haben wir es hier zu tun) würde ich erst gar
nicht auf solche Ideen bringen. Surprised)

Ich gebe zu, dass solche Techniken nicht unbedingt im Code eines
Anfängers gehören. Aber in Grunde genomment denke ich, dass man relativ
früh die Verteilung der Aufgaben zwischen [io]stream und streambuf
verstehen soll. Wenn ich auch den OP lesen, habe ich den Eindruck, dass
er es mindestens teilweise versteht. Ich wurde sogar sagen, dass sein
Problem ein typischer Fall ist, wo man einen istream statt einer davon
abgeleiteten Klasse verwenden soll.

Leiter sagt er uns nicht, warum es scheitert. Ich sehe kein Problem mit
etwas wie:

Target::Target( ostream& os )
: outStream( os.rdbuf() )
{
}

Target::Target( std::string const& pathToFile )
: outStream( new std::filebuf( pathToFile )
{
if ( ! static_cast< std::filebuf* >(
outStream.rdbuf() )->is_open() ) {
throw ??? ;
}
}

(Na ja. Ich sehe in der Tat einige Probleme. Wie z.B.: wer soll den neu
allokierten filebuf befreien? Aber der Grundprinzip soll funktionnieren.)

Immerhin wäre es interessant, genauer zu wissen, was er erreichen will.
Er hat z.B. gesagt, dass er gleichzeitig in mehrere Streams schreiben
will. Ich sehe nicht, dagegen, wie er sowas mit dieser Lösung erreichen
will; sein Fluß enthält immer nur einen Ziel.

Zum gleichzeitigen Schreiben nach mehreren Zielen, mit möglichst
unterschiedenen Filtern, benutzt man naturlich filtrierende streambuf,
siehe z.B. meine FilteringOutputStream unter Util/IO im Code-Bereich bei
mir. Insbesonders den Beispiel LoggingInserter. Aber Vorsicht: der
Beispiel ist genau das, und stellt eine ganz einfache Benutzung dar. In
der Tat, wenn man mehrere Ziele hat, muss man als aller erst eine
Fehlerpolitik definieren. Ist es Fehler, wenn nur einen Fluß nicht
schreiben kann, oder nur wenn kein schreiben kann, oder...?

--
James Kanze GABI Software http://www.gabi-soft.fr
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
harrisx
Guest





PostPosted: Tue Oct 05, 2004 1:19 pm    Post subject: Re: Sorgenkind ostream Reply with quote

Hallo,

vielen Dank für Eure schnelle und ausführliche Hilfe. Das
Resultat: es funktioniert jetzt! - Und ich habe einiges über
streams gelernt, was ich vorher tatsächlich nicht verstanden
hatte.

Ich habe es erstmal mit der Lösung von Chris versucht, weil
das meiner ursprünglichen Idee am nächsten war. Das ganze
hatte ja sogar schon funktioniert wie ich es wollte solange
ich nur ofstreams (die sind in einer list abgespeichert und
werden sozusagen abgeklappert, ob sie was zum Wegschreiben
annehmen wollen) genommen habe. Als ich dann aber auch cout
und cerr mit aufnehmen wollte, war ich gezwungen ostream
zu verwenden und da fingen meine Probleme an. Vielleicht
hätte ich es von Anfang an mit einer Weiche machen
sollen, aber das hat sich mir gedanklich leider
nicht gerade aufgedrängt ;-)

nochmal vielen Dank und viele Grüße
Harris

--
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.