🚀 go-pugleaf

RetroBBS NetNews Server

Inspired by RockSolid Light RIP Retro Guy

Article View: de.comp.lang.c++
Article #1839

Re: Probleme beim Vererben von fstream

#1839
From: Dietmar Kuehl
Date: Fri, 15 Mar 1996 19:42
167 lines
8388 bytes
Hi,
Bernhard Ruch (Bernhard.Ruch@studi.epfl.ch) wrote:
: Dietmar Kuehl wrote:
: > Bernhard Ruch (Bernhard.Ruch@studi.epfl.ch) wrote:
: > : Ich moechte eine neue Klasse ObjectStream definieren, die von der
: > : Klasse fstream vererbt wird. Zusaetzlich zu den gewoehnlichen
: > : fstream-Operationen soll das Lesen und Schreiben von Objekten
: > : moeglich sein.

[Beschreibung von dem, was ich fuer die vorgesehene Benutzung von
'[io]stream' abgeleiteten Klasse halte, geloescht...]

: Ich muss vielleicht die Ausgangslage genauer beschreiben:

Bei dem was Du Dir da eingebrockt hast, ist das allerdings neotig...!

: Ich benoetige eine Klasse ObjectStream, welche die folgenden Operatoren enthaelt:
: (Da dies Spezifikationen meines Projektes sind, kann ich sie nicht aendern)

<<< WARNUNG: Meine persoenliche Meinung ohne genau Kenntnis des Systems: BEGIN >>>
Ich kann, ohne genaues Wissen ueber das System, was gebaut werden soll,
natuerlich keinen wirklich qualifizierten Kommentar zu dessen Design
abgeben, aber ich denke dennoch, dass an dieser Stelle das Design FUBAR
ist: Hier waere es sicher ratsam gewesen, sich VOR der Spezifikation zu
informieren, wie man IOstreams benutzt.
<<< Meinung, Flame: END >>>

: 	ObjectStream &operator << (char);
: 	ObjectStream &operator << (int);
: 	ObjectStream &operator << (float);
: 	etc.

: 	ObjectStream &operator >> (char &);
: 	ObjectStream &operator >> (int &);
: 	ObjectStream &operator >> (float &);
: 	etc.

: 	ObjectStream &operator << (const Object &);
: 	ObjectStream &operator >> (Object &);
: 	ObjectStream &operator << (const Object *);
: 	ObjectStream &operator >> (Object **);
: 	u.a.

: Dies antwortet auf die Frage, WAS geschrieben und gelesen werden soll.

OK, hier ist womoeglich ein Super-GADF (groesster anzunehmender
Design-Fehler) auszubuegeln. Als erstes ein Versuch der
Schadensbegrenzung, mit dem man das alles noch unter den Teppich kehren
kann (typisches vorgehen, etwa bei Unfaellen im Zusammenhang mit
Kernkraftwerken): Wenn die Spezifikation ist das folgendes legaler Code
sein soll:

    void f(ObjectStream &OS, Object const &o) { OS << o; }

(analog die anderen Operatoren fuer 'ObjectStream' die mit 'Object'
bzw. "u.a" arbeiten) und NICHT gefordert ist, dass es einen Member
'ObjectStream::operator<< (Object const &)' gibt (und auch keiner von
den anderen inklusive "u.a.") dann kann man noch was retten: man kommt
sogar mit einem blauen Auge (durch meine Kritik und ggf. die [kleinere]
Spezifikationsaenderung) weg. Der Ansatz ist dann einfach, dass man
virtuell je eine Klasse von 'ifstream' und 'ofstream' ableitet (etwa
'iObjstStream' und 'oObjectStream') und dann 'ObjectStream' von den
beiden anderen Klassen ableitet. Die passenden Funktionen fuer alle
vorhanden Inserters und Extractor werden geerbt und man fuegt die neuen
so zu, wie ich es in meinem vorherigen Artikel geschrieben habe.

Wann dieser Ansatz fehlschlaegt, sieht es schon duesterer aus. Jetzt
kommt zur Schadensabwendung schon richtig Arbeit auf Dich zu: Da Du die
Operatoren fuer 'Object' und Verwandte als Member von 'ObjectStream'
definieren MUSST (das sagt ja dann offenbar Deine Spezifikation, sonst
waere der Fall oben eingetreten), werden schonmal alle Operatoren fuer
vorhandene Typen versteckt. Sie muessen fuer 'ObjectStream' wieder
sichtbar gemacht werden und zwar so, dass sie einen 'ObjectStream'
zurueckliefern, also sind Funktionen der folgenden Art faellig:

  ObjectStream &operator<< (char c)
  {
    ostream::operator<< (c);
    return *this;
  }

Nicht viele, da die Anzahl von 'ostream::operator<<(T)' begrenzt ist
(zwanzig oder so).  Analog fuer 'operator>>()'. Aber das reicht
vermutlich noch nicht: Wenn alle anderen geschriebenen Inserter und
Extractor Funktionen auch noch funktionieren sollen, dann muessen die
auch einen 'ObjectStream' liefern. Die einfachste Moeglichkeit duerfte
dafuer folgendes sein:

  template <class T>
  inline ObjectStream &operator << (ObjectStream &OS, T const &t)
  {
    operator<< (static_cast<ostream&>(OS), t);
    return OS;
  }

Analog fuer 'operator>>()'. Was u.U. noch bleibt sind die verschiedenen
Manipulatoren.  Allerdings denke ich, dass die dadurch auch erschlagen
worden sind...

: Da es schon verschiedene Stream-Klassen gibt, welche die Operatoren <<
: und >> fuer die vordefinierten Typen (char, int, etc) enthalten, schien
: es mir das einfachste zu sein, diese Operatoren wiederzuverwenden, indem
: meine Klasse ObjectStream von einer dieser Stream-Klassen vererbt wird,
: und dann die neuen Operatoren hinzuzufuegen.	

Der subtile Unterschied zwischen Deiner Beschreibung und der
tatsaechlichen Implementation ist der: Es gibt jeweils genau EINE
Klasse, welche die Operatoren << bzw. >> fuer die built-in Typen
definiert: 'ostream' bzw. 'istream'. Die anderen Klassen definieren
KEINEN derartigen Operator, sondern erben ALLE! Das ist elementar
wichtig, da sonst eben gerade die passenden Operatoren versteckt sind.
Wie ich schon in meinem vorherigen Artikel geschrieben habe, sind die
von 'ostream' (bzw. 'istream') abgeleiteten Klassen nur fuer den
Komfort da: Damit man 'ofstream file("foobar")' schreiben kann und
nicht

  auto_ptr<filebuf> fb = new filebuf("foobar");
  ostream file(fb.get());

schreiben muss.

: Nun zur Frage, WIE geschrieben und gelesen werden soll: Da diese Operatoren
: auf ein File angewendet werden sollen, draengte es sich auf, die Klasse 
: ObjectStream von fstream (anstatt iostream) zu vererben, da sie somit alle
: File-spezifischen Eigenschaften von fstream wiederverwenden kann.

Da faellt mir eigentlich nur ein: RTFM. ... und zwar bevor man die
Spezifikation fuer ein Projekt akzeptiert! Wenn moeglich, empfehle ich
Dir dringend, ueber eine Aenderung der Spezifikation zu verhandeln, so
dass zumindest die erste von mir beschriebene Technik moeglich wird!
Wenn irgend moeglich, sollte auch 'ObjectStream' aus der Spezifikation
verschwinden.

: > : Wenn ich nun versuche, diesen Code zu compilieren, meldet der Compiler,
: > : dass er keinen Operator << fuer (ObjectStream, int) kenne, obwohl ja
: > : ObjectStream von fstream abgeleitet ist und diesen Operator kennen
: > : muesste:
: > 
: > :   g++ -c Test.cc
: > :   Test.cc: In method `void Object::SaveData(class ObjectStream &)':
: > :   Test.cc:20: no match for `operator <<(class ObjectStream, int)'
: > 
: > Der Compiler hat recht! Er sieht nur den 'operator << (ObjectStream,
: > Object &)', alle anderen Funktionen mit dem gleichen Namen (in diesem
: > Fall 'operator <<') sind versteckt.  Wenn Du sie wirklich benutzen
: > wolltest (was Du aber in diesem Fall gar nicht wirklich willst, siehe
: > oben), dann koenntest Du es forcieren, z.B. mit 'ostream::operator<<
: > (17)'.

: Gibt es eine andere Art, die vordefinierten Operatoren <<, >> und die
: File-spezifischen Eigenschaften von fstream wiederzuverwenden und 
: neue Stream-Operatoren hinzuzufuegen, als von einer Stream-Klasse
: zu vererben?

Ja. Wie ich schon in meinem vorherigen Artikel beschrieben habe, gibt
es eigentlich ueberhaupt keinen Grund, von 'fstream' (oder 'ofstream'
bzw. 'ifstream', da es ja 'fstream' im Standard eh nicht gibt)
abzuleiten, um weitere Operatoren << bzw. >> inzuzufuegen: Schreib
Inserter- und Extractor- Funktionen fuer 'ostream' bzw. 'istream' und
alle funktioniert, wie man es eigentlich gerne haette. ... und noch
mehr: Es funktionert naemlich fuer ALLE Streams! Das ist DIE Technik,
um sowas zu machen. So gehoert (mit allerhoechster Wahrscheinlichkeit)
die Spezifikation fuer Dein Projekt definiert!
--
dietmar.kuehl@uni-konstanz.de
http://www.informatik.uni-konstanz.de/~kuehl
I am a realistic optimist - that's why I appear to be slightly pessimistic
Technical Details
Message-ID: <4ich6q$aol@news.BelWue.DE>
Path: arc1-ca.pugleaf.net!news.belwue.de!uzwil!kuehl
References: <31486437.41C6@studi.epfl.ch> <4ia5sb$cfk@news.BelWue.DE> <3149644C.41C6@studi.epfl.ch>

Show Full Headers
Complete Article Headers
Path: arc1-ca.pugleaf.net!news.belwue.de!uzwil!kuehl
From: kuehl@uzwil.informatik.uni-konstanz.de (Dietmar Kuehl)
Newsgroups: de.comp.lang.c++
Subject: Re: Probleme beim Vererben von fstream
Date: 15 Mar 1996 19:42:18 GMT
Organization: Fakultät für Mathematik und Informatik
Message-ID: <4ich6q$aol@news.BelWue.DE>
References: <31486437.41C6@studi.epfl.ch> <4ia5sb$cfk@news.BelWue.DE> <3149644C.41C6@studi.epfl.ch>
Reply-To: dietmar.kuehl@uni-konstanz.de
NNTP-Posting-Host: uzwil.informatik.uni-konstanz.de
X-Newsreader: TIN [version 1.2 PL2]