Your Browser is not longer supported

Please use Google Chrome, Mozilla Firefox or Microsoft Edge to view the page correctly
Loading...

{{viewport.spaceProperty.prod}}

sbufprot Geschützte Schnittstelle der Zeichenpuffer-Klasse

&pagelevel(3)&pagelevel


In diesem Abschnitt werden die geschützten und virtuellen Teile der Klasse streambuf beschrieben. Diese Teile sind insbesondere bei der Nutzung abgeleiteter Klassen von Interesse.


#include <iostream.h>

typedef long streamoff, streampos;

class ios
{

public:
enum seek_dir {beg, cur, end};
enum open_mode {in, out, ate, app, trunc, nocreate, noreplace,

bin, tabexp};

// und viele weitere Deklarationen, siehe ios ...

} ;

class streambuf

{

public:


streambuf();
streambuf(char* p, int len);

virtual
void

˜streambuf();
dbp();

protected:

int
char*
int
char*
char*
char*
char*
void
char*
char*
void
char*
void
void
void
int
void
virtual int

allocate();
base();
blen() const;
eback();
ebuf();
egptr();
epptr();
gbump(int n);
gptr();
pbase();
pbump(int n);
pptr();
setb(char* b, char* eb, int a=0);
setg(char* eb, char* g, char* eg);
setp(char* p, char* ep);
unbuffered() const;
unbuffered(int);
doallocate();

public:

virtual int
virtual int

overflow(int c=EOF);
pbackfail(int c);

virtual streampos 


seekoff(streamoff, ios::seek_dir, int =ios::in|ios:out);

virtual streampos


seekpos(streampos, int =ios::in|ios:out);

virtual streambuf*


setbuf(char* p, int len);

virtual int
virtual int

sync();
underflow();

};



streambuf-Objekte implementieren die Pufferabstraktion, die im Abschnitt zu sbufpub beschrieben wird. Die Klasse streambuf selbst enthält nur die grundlegenden Elemente zur Zeichenmanipulation; üblicherweise wird im Programm eine aus streambuf abgeleitete Klasse eingesetzt. In diesem Abschnitt wird die Schnittstelle beschrieben, die der Programmierer zum Kodieren einer abgeleiteten Klasse benötigt.

Die Elementfunktionen von streambuf können - vereinfacht - in zwei Gruppen unterteilt werden. Die nicht-virtuellen Funktionen manipulieren streambuf-Objekte so, wie dies in abgeleiteten Klassen erforderlich ist. Die Beschreibungen zeigen Implementationsdetails,die in einer öffentlichen Schnittstelle nicht erscheinen sollten. Durch die virtuellen Funktionen können abgeleitete Klassen als Spezialfälle der Klasse streambuf entwickelt werden, die auf die entsprechenden Quellen und Ziele (von Zeichenübertragungen) ausgelegt sind.

Die Beschreibung der virtuellen Funktionen enthält auch die "Pflichtaufgaben" der virtuellen Funktionen in den abgeleiteten Klassen. Wenn sich die virtuellen Funktionen erwartungsgemäß verhalten, ist auch das korrekte Verhalten der öffentlichen Schnittstelle von streambuf sichergestellt. Anderenfalls kann das Verhalten von streambuf allerdings Unregelmäßigkeiten aufweisen. In diesem Fall verhält sich auch ein iostream-Objekt (oder anderer Programmcode), das vom korrekten streambuf-Verhalten abhängt, anders als erwartet.

Bei den folgenden Beschreibungen wird angenommen, dass:

  • sb vom Typ streambuf* ist.
  • ptr, b, eb, p, ep, g und eg vom Typ char* sind.
  • c ein int-Zeichen (positiv oder EOF) ist.
  • pos vom Typ streampos (siehe sbufpub) ist.
  • off vom Typ streamoff ist.
  • dir vom Typ seekdir ist.
  • mode eine int-Zahl ist, die open_mode darstellt.

Konstruktoren

streambuf()

Ein leerer Puffer wird angelegt, der einer leeren Folge entspricht.

streambuf(char * b, int len)

Ein leerer Puffer wird angelegt und der Reservierungsbereich auf len Bytes, beginnend bei b, gesetzt.

Die Bereiche get, put und der Reservierungsbereich

Die protected-Elemente von streambuf stellen die Schnittstelle zu den abgeleiteten Klassen dar, die in drei Bereichen (Byte-Felder) strukturiert sind. Die Bereiche werden gemeinsam von Basis- und abgeleiteten Klassen verwaltet und werden get, put und Reservierungsbereich (oder Puffer) genannt. Die Bereiche get und put sind üblicherweise nicht identisch, können aber den Reservierungsbereich überlappen. Der Reservierungsbereich ist in erster Linie eine Ressource, aus der Kapazität für die Bereiche put und get belegt werden kann. Die Bereiche get und put werden beim Einfügen und Entnehmen von Zeichen in den/aus dem Puffer verändert, der Reservierungsbereich ist aber im allgemeinen festgelegt. Die Bereiche werden durch eine Reihe von char*-Werten definiert. Die Pufferabstraktion wird in Form von Zeigern beschrieben, die zwischen die Zeichenzeigen. Die char*-Werte zeigen aber auf char-Objekte (Zeichen). Das Erstellen einer Beziehung mit den char*-Werten kann man sich so vorstellen, dass der Zeiger vor das Byte gerichtet ist, auf das er eigentlich zeigt.

Funktionen zur Untersuchung von Zeigern

char * ptr=sb→base()

Ein Zeiger auf das erste Byte des Reservierungsbereiches wird geliefert. Der Bereich zwischen sb->base() und sb->ebuf() ist der Reservierungsbereich.

char * ptr=sb->eback()

Ein Zeiger auf die untere Grenze von sb->gptr() wird geliefert. Der Bereich zwischen sb->eback() und sb->gptr() ist zum "Zurückschieben" von Zeichen verfügbar.

char * ptr=sb->ebuf()

Ein Zeiger auf das erste Byte hinter dem Reservierungsbereich wird geliefert.

char * ptr=sb->egptr()

Ein Zeiger auf das erste Byte hinter dem Bereich get wird geliefert.

char * ptr=sb->epptr()

Ein Zeiger auf das erste Byte hinter dem Bereich put wird geliefert.

char * ptr=sb->gptr()

Ein Zeiger auf das erste Byte des Bereiches get wird geliefert. Die verfügbaren Zeichen befinden sich zwischen sb->gptr() und sb->egptr(). Das nächste zu entnehmende Zeichen ist *(sb->gptr()), sofern sb->egptr() nicht kleiner als oder gleichsb->gptr() ist.

char * ptr=sb->pbase()

Es wird ein Zeiger auf die Basis des put-Bereichs geliefert. Die Zeichen zwischen sb->pbase() und sb->pptr() sind im Puffer gespeichert und wurden noch nicht verbraucht.

char * ptr=sb->pptr()

Es wird ein Zeiger auf das erste Byte des Bereiches put geliefert. Der Bereich zwischen sb->pptr() und sb->epptr() ist der put-Bereich. Hier sind Zeichen gespeichert.

Funktionen zum Setzen der Zeiger

Hinweis

Als Hinweis darauf, daß ein Bereich (get, put oder Reservierungsbereich) nicht existiert, sollten alle damit verknüpften Zeiger auf Null gesetzt werden.

void sb->setb(char * b, char * eb, int i)

base() und ebuf() werden auf b bzw. eb gesetzt. Die Angabe i legt fest, ob der
Bereich für die automatische Löschung vorgesehen ist. Wenn i ungleich 0 ist, wird bbei einer Änderung von base durch einen Aufruf von setb() oder beim Aufruf des Destruktors für *sb gelöscht. Wenn sowohl b als auch eb 0 sind, ist kein Reservierungsbereich verfügbar. Ist b ungleich 0, so ist ein Reservierungsbereich auch dann vorhanden, wenn eb kleiner als b ist und der Reservierungsbereich daher die Länge 0aufweist.

void sb->setp(char * p, char * ep)

pptr() wird auf p, pbase() auf p und epptr() auf ep gesetzt.

void sb->setg(char * eb, char * g, char * eg)

eback() wird auf eb, gptr() auf g und egptr() auf eg gesetzt.

Weitere nicht-virtuelle Elementfunktionen

int i=sb->allocate()

Es wird versucht, einen Reservierungsbereich anzulegen. Wenn bereits ein Reservierungsbereich existiert oder wenn sb->unbuffered() ungleich 0 ist, liefert die Funktion allocate() den Wert 0, ohne dass eine weitere Operation vorgenommen wurde. Beim erfolglosen Versuch der Speicherzuweisung liefert allocate() den Wert EOF; anderenfalls (also bei erfolgreicher Zuweisung) wird der Wert 1 zurückgegeben. Die Funktion allocate() wird von keiner der nicht-virtuellen Elementfunktionen von streambuf aufgerufen.

int i=sb->blen()

Die Größe (in char-Einheiten) des aktuellen Reservierungsbereichs wird geliefert.

void dbp()

Die Funktion schreibt Pufferstatus-Informationen im EBCDIC-Format direkt in die Einheit, die mit dem Dateideskriptor 1 verknüpft ist. Diese Funktion wurde zu Testzwecken eingefügt; es sind keine Spezifikationen zum Format der Ausgabe vorgegeben.
Die Funktion wird als Teil der geschützten Schnittstelle angesehen, da die ausgegebenen Informationen nur im Zusammenhang mit der Schnittstelle sinnvoll sind. Die Funktion ist als public deklariert, damit sie beim Testen des Programms an beliebiger
Stelle aufgerufen werden kann.

void sb->gbump(int n)

gptr() wird um den Wert n inkrementiert, wobei n positiv oder negativ sein kann. Es wird nicht geprüft, ob der neue Wert von gptr() in den erlaubten Grenzen liegt.

void sb->pbump(int n)

pptr() wird um den Wert n inkrementiert; n kann positiv oder negativ sein. Es wird nicht geprüft, ob der neue Wert von pptr() in den erlaubten Grenzen liegt.

void sb->unbuffered(int i)
int i=sb→unbuffered()

Es gibt eine private-Variable, die den Status der Pufferung von sb beschreibt. sb->unbuffered(i) setzt den Wert dieser Variable auf i, während sb->unbuffered()
den aktuellen Variablenwert liefert. Diese Statusangabe erfolgt unabhängig von der tatsächlichen Belegung des Reservierungsbereichs. Die Variable dient primär dazu,festzustellen, ob der Reservierungsbereich automatisch durch allocate() reserviert wurde.

Virtuelle Elementfunktionen

Virtuelle Funktionen können in abgeleiteten Klassen erneut definiert werden, um das Verhalten von streambuf-Objekten genauer festzulegen. In diesem Abschnitt wird das Soll-Verhalten der virtuellen Funktionen in den abgeleiteten Klassen beschrieben. Im nächsten Abschnitt finden Sie eine Beschreibung des Verhaltens dieser Funktionen in der Basisklasse streambuf.

int i=sb->doallocate()

Die Funktion wird aufgerufen, wenn allocate() bestimmt, dass Speicherbereich benötigt wird. doallocate() wird zum Aufruf von setb() verwendet, damit ein Reservierungsbereich bereitgestellt oder - wenn dies nicht möglich ist - der Wert EOF geliefert wird.Der Aufruf erfolgt nur, wenn sb->unbuffered() und sb->base() gleich 0 sind.

int i=overflow(int c)

Diese Funktion "verbraucht" Zeichen. Wenn c nicht das Zeichen EOF ist, muß die Funktion overflow() c entweder sichern oder verbrauchen. Die Funktion wird üblicherweise aufgerufen, wenn der Bereich put gefüllt ist und das Speichern eines weiteren Zeichens versucht wurde. Der Aufruf ist aber auch in anderen Fällen möglich. Üblicherweise werden durch den Aufruf die Zeichen zwischen pbase() und pptr() verbraucht, setp() wird aufgerufen, um einen neuen put-Bereich anzulegen, und c wird über die Funktion sputc() gespeichert, wenn c!=EOF ist. sb->overflow() sollte zur Anzeige eines Fehlers den Wert EOF liefern, anderenfalls sollte eine andere Rückgabe erfolgen.

int i=sb->pbackfail(int c)

Die Funktion wird aufgerufen, wenn eback() gleich gptr() ist und versucht wurde, das Zeichen c "zurückzuschieben". Wenn diese Situation korrekt gehandhabt werden kann(beispielsweise durch Repositionieren in einer externen Datei), sollte pbackfail() das Zeichen c liefern; anderenfalls sollte EOF zurückgegeben werden.

streampos pos=sb->seekoff(streamoff off, seekdir dir, int mode)

seekoff() ist eine öffentliche virtuelle Elementfunktion. Eine detaillierte Beschreibung finden Sie im Abschnitt Abschnitt sbufpub. Die get- und/oder put-Zeiger werden neu positioniert. Diese Positionierung wird nicht von allen abgeleiteten Klassen unterstützt.

streampos pos=sb->seekpos(streampos pos, int mode)

seekpos() ist eine öffentliche virtuelle Elementfunktion. Eine detaillierte Beschreibung finden Sie im Abschnitt Abschnitt sbufpub. Die get- und/oder put-Zeiger werden neu positioniert. Diese Positionierung wird nicht von allen abgeleiteten Klassen unterstützt.

streambuf * sb=sb->setbuf(char * ptr, int len)

Das Feld, das bei ptr beginnt und len byte lang ist, wird als Reservierungsbereich angeboten. Üblicherweise wird ein Aufruf als Anforderung interpretiert, sb ohne Pufferung anzulegen, wenn ptr oder len gleich 0 sind. Die abgeleitete Klasse kann - muss aber nicht - diesen Bereich nutzen. Auch die Anforderung des nicht gepufferten Status kann akzeptiert oder ignoriert werden. setbuf() sollte sb liefern, wenn die Anforderung erfüllt wird; anderenfalls sollte der Wert 0 zurückgegeben werden.

int i=sb→sync()

sync() ist eine öffentliche virtuelle Elementfunktion. Eine detaillierte Beschreibung finden Sie im Abschnitt sbufpub.

int i=sb→underflow()

Die Funktion wird zur Bereitstellung von Zeichen eingesetzt. Hierdurch kann beispielsweise eine Situation geschaffen werden, in der ein Bereich get vorliegt, der nicht leer ist. Erfolgt der Aufruf, wenn Zeichen im Bereich get vorliegen, sollte die Funktion das erste verfügbare Zeichen liefern. Im Fall eines leeren Bereichs get sollte zunächst einnicht leerer Bereich get angelegt und das nächste Zeichen (das im Bereich get verbleiben sollte) geliefert werden. Wenn keine weiteren Zeichen verfügbar sind, sollte die Funktion underflow() den Wert EOF liefern und einen leeren Bereich get hinterlassen.

Die Standarddefinitionen der virtuellen Funktionen

int i=sb→streambuf::doallocate()

Die Zuweisung von Speicherkapazität an einen Reservierungsbereich wird über den Operator new versucht.

int i=sb->streambuf::overflow(int c)

streambuf::overflow() sollte behandelt werden, als wäre das Funktionsverhalten nicht definiert. Das bedeutet, dass abgeleitete Klassen die Funktion immer definieren sollten.

int i=sb->streambuf::pbackfail(int c)

Beim Auftreten eines Fehlers wird EOF und bei erfolgreicher Ausführung wird c geliefert.

streampos pos=sb->streambuf::seekpos(streampos pos, int mode)

Es wird sb->seekoff(streamoff(pos),ios::beg,mode) geliefert. Zur Definition der Repositionierung in einer abgeleiteten Klasse ist es häufig nur nötig, seekoff() zu definieren und die ererbte Funktion streambuf::seekpos() einzusetzen.

streampos pos=sb->streambuf::seekoff(streamoff off, seekdir dir, int mode)

EOF wird geliefert.

streambuf * sb=sb->streambuf::setbuf(char* ptr, int len)

Die Anforderung wird erfüllt, wenn kein Reservierungsbereich vorhanden ist.

int i=sb->streambuf::sync()

Der Wert 0 wird geliefert, wenn der Bereich get leer ist und keine nicht verbrauchten Zeichen vorliegen. Andernfalls wird EOF geliefert.

int i=sb->streambuf::underflow()

streambuf::underflow() sollte behandelt werden, als wäre das Funktionsverhalten
nicht definiert. Das bedeutet, daß die Funktion in abgeleiteten Klassen immer definiert werden sollte.

BEISPIEL

Das Programm gibt die Adresse des Basisbereiches einer aus streambuf abgeleiteten Klasse aus.

Das Programm ist ein Beispiel zur Darstellung von Speicherinhalten. Es hätten andere trivial-Elementfunktionen, wie get_base, verwendet werden können, die die Adressen der Bereiche get und put liefern.

#include <iostream.h>
const int N = 20;
class trivial : public streambuf
{
  int a;                /* Einige Beispieldaten in einer Klasse */
  public:
  trivial() : streambuf(new char[ N], N)
  {
    /* trivial-Konstruktor wird durch streambuf-Konstruktor     */
    /*definiert*/
    a = 0;
  };
   ̃trivial() {};
  /* Annahme, daß der streambuf-Destruktor den N Byte großen    */
  /* Reservierungsbereich löscht                                */
  char * get_base()
  {
    /* Diese Funktion wird benötigt, da die Elementfunktion     */
    /* streambuf::base() geschützt ist.                         */
    /* Qualifikation streambuf:: wird nicht benötigt, da        */
    /* Gültigkeitsbereich ok ist.                               */
    return base();
  };
};
int main()
{
  trivial test_var;
  cout << (void *) test_var.get_base() << endl;
  /* Umwandlung nach void *, damit cout nicht den Inhalt des     */
  /* ersten Byte des Reservierungsbereiches anzeigt.             */
  return 0;
}

Das Ergebnis der Programmausführung ist:

0xc6008
%  CCM0998 Verbrauchte CPU-Zeit: 0.0005 Sekunden

Beachten Sie, dass der im Zeiger gespeicherte Wert variieren kann und dass cout ein Standardformat für Zeigerwerte aufweist.

BESONDERHEITEN


Die Konstruktoren wurden als public deklariert, um die Kompatibilität zum älteren stream-Paket zu erhalten. Sie sollten als protected deklariert sein.

Die Schnittstelle für nicht gepufferte Operationen ist unhandlich. Die Entwicklung der virtuellen Funktionen underflow() und overflow() mit korrektem Verhalten für ungepufferte streambuf-Objekte ist ohne besondere Vorkehrungen kompliziert. Zudem gibt es für virtuelle Funktionen keine Möglichkeit, gesondert auf get- und put-Operationen zureagieren, die mehrere Zeichen umfassen.

Obwohl die öffentliche Schnittstelle der Klasse streambuf in Zeichen und Bytes beschrieben wird, arbeitet die Schnittstelle zu abgeleiteten Klassen mit char-Objekten. Da eine Entscheidung bezüglich des Typs der tatsächlichen Datenzeiger getroffen werden musste, erschien es einfacher, dies durch die Datentypen der protected-Elemente wiederzugeben, als alle Elemente doppelt zu implementieren (in einer char- und unsigned char-Version). Vielleicht hätten auch alle Einsatzbereiche von char* über eine typedef-Anweisung realisiert werden sollen.

SIEHE AUCH


istream, sbufpub