Rogue Wave banner
Previous fileTop of documentContentsIndexNext file

Section 6: Using Virtual Streams

The iostream facility that comes with every C++ compiler is a resource that should be familiar to you as a C++ developer. Among its advantages are type-safe insertion and extraction into and out of streams, extensibility to new types, and transparency to the user of the source and sink of the stream bytes, which are set by the class streambuf.

But the iostream facility suffers from a number of limitations. Formatting abilities are particularly weak; for example, if you insert a double into an ostream, there is no type-safe way to insert it as binary. Furthermore, not all byte sources and sinks fit into the streambuf model. For many protocols, such as XDR, the format is intrinsically wedded to the byte stream and cannot be separated.

The Rogue Wave virtual streams facility overcomes these limitations by offering an idealized model of a stream. No assumptions are made about formatting, or stream models. At the root of the virtual streams class hierarchy is class RWvios. This is an abstract base class with an interface similar to the standard library class ios:

class RWvios{
public:
  virtual int   eof()             = 0;
  virtual int   fail()            = 0;
  virtual int   bad()             = 0;
  virtual int   good()            = 0;
  virtual int   rdstate()         = 0;
  virtual int   clear(int v = 0)  = 0;
};

Classes derived from RWvios will define these functions.

Inheriting from RWvios are the abstract base classes RWvistream and RWvostream. These classes declare a suite of pure virtual functions such as operator<<(), put(), get(), and the like, for all the basic built-in types and arrays of built-in types:

class RWvistream : public RWvios {
public:
  virtual Rwvistream&  operator>>(char&)       = 0;
  virtual Rwvistream&  operator>>(double&)     = 0;
  virtual int          get()                   = 0;
  virtual Rwvistream&  get(char&)              = 0;
  virtual Rwvistream&  get(double&)            = 0;
  virtual Rwvistream&  get(char*, size_t N)    = 0;
  virtual Rwvistream&  get(double*, size_t N)  = 0;
  .
  .
  .
};

class RWvostream : public RWvios {
public:
  virtual Rwvostream&  operator<<(char)             = 0;
  virtual Rwvostream&  operator<<(double)           = 0;
  virtual Rwvostream&  put(char)                    = 0;
  virtual Rwvostream&  put(double)                  = 0;
  virtual Rwvostream&  put(const char*, size_t N)   = 0;
  virtual Rwvostream&  put(const double*, size_t N) = 0;
  .
  .
  .
};

Streams that inherit from RWvistream and RWvostream are intended to store built-ins to specialized streams in a format that is transparent to the user of the classes.

The basic abstraction of the virtual streams facility is that built-ins are inserted into a virtual output stream, and extracted from a virtual input stream, without any regard for formatting. In other words, there is no need to pad output with whitespace, commas, or any other kind of formatting. You are effectively telling RWvostream, "Here is a double. Please store it for me in whatever format is convenient, and give it back to me in good shape when I ask for it."

The results are extremely powerful. You can write and use streaming operators without knowing anything about the final output medium or formatting to be used. For example, the output medium could be a disk, memory allocation, or even a network. The formatting could be in binary, ASCII, or network packet. In all of these cases, you use the same streaming operators.


Previous fileTop of documentContentsIndexNext file
©Copyright 1999, Rogue Wave Software, Inc.
Send mail to report errors or comment on the documentation.