iostream examples

Deriving new streambuf classes

The streambuf class is intended to serve as a base class. Although it contains members to manipulate the sequences, it does not contain any mechanism for producing or consuming characters. These must be provided by a derived class. The iostream library contains several such derived streambuf classes, but a program may define new ones.

The members of a class that are intended for use by derived classes are protected, and the data structure as seen by a derived class is said to be the protected interface of the streambuf class. This abstraction exposes the details of the array management that is implicit in the buffering provided by streambufs. It consists of two parts. The first part is member functions of streambuf that permit access to and manipulation of the arrays and pointers used to implement the sequence abstraction. The second part is virtual members of streambuf that must be supplied by the derived class.

The principle example of this subtopic will be the implementation of fctbuf, whose declaration looks like:

   typedef int (*action)(char* b, int n, open_mode m) ;

class fctbuf : public streambuf { public: fctbuf(action f,open_mode m) ; private: ... } ;

When called with m=ios::out, an action() function processes the n characters starting at b. When called with m=ios::in, it stores n characters starting at b. It returns non-zero to indicate success and zero to indicate failure.

The declaration of fctbuf looks like:

   class fctbuf : public streambuf {
   public:			// constructor
   	fctbuf(action a, open_mode m) ;

private: // data members action fct ; open_mode mode ; char small[1] ;

protected: // virtuals int overflow(int) ; int underflow() ; streambuf* setbuf(char*,int,int) ; int sync() ;

} ;

The constructor just initializes the data elements. The action function a will be called only in modes compatible with m.

   fctbuf::fctbuf(action a, open_mode m)
   	: fct(a), mode(m) { }

The virtual functions define details that make fctbuf() behave properly. The streambuf protected interface is organized around three areas (char arrays), the holding area, the get area, and the put area. Characters are stored into the put area and fetched from the get area.

As characters are stored in the put area, it shrinks until there is no more space available. If an attempt is made to store a character when the put area has no space, a new area must be established. Before that can be done the old characters must be consumed. Both these tasks are the responsibility of the overflow() function. Similarly, the get area is shrunk by fetches and is eventually empty. If more characters are needed the underflow() function must create a new get area. Both overflow() and underflow() will use the holding area to initialize the put or get area (respectively).

Next topic: setbuf
Previous topic: Using streambufs in streams

© 2004 The SCO Group, Inc. All rights reserved.
UnixWare 7 Release 7.1.4 - 27 April 2004