Apache C++ Standard Library User's Guide

## 38.3 Construction and Initialization

All standard stream templates are derived from `std::basic_ios`. In C++, a virtual base class is initialized by its most derived class; that is, our new `odatstream` class is responsible for initialization of its base `std::basic_ios`. Now `basic_ios` has only one public constructor, which takes a pointer to a stream buffer. This is because `basic_ios` contains a pointer to the stream buffer, which has to be initialized when a `basic_ios` subobject is constructed. Consequently, we must figure out how to provide a stream buffer to our base class. Let's consider two options:

- Derivation from file stream or string stream classes; that is, class
  `std::{i,o}fstream` or class `std::{i,o}stringstream`, and

- Derivation from `std::basic_{i,o}stream`.

### 38.3.1 Derivation from File Stream or String Stream Classes std::{i,o}fstream or std::{i,o}stringstream

The file and string stream classes contain a stream buffer data member and already monitor the initialization of their virtual base initialization by providing the pointer to their own stream buffer. If we derive from one of these classes, we do not provide another stream buffer pointer because it would be overwritten by the file or string stream's constructor anyway. (Remember that virtual base classes are constructed before non-virtual base classes regardless of where they appear in the hierarchy.) Consider:

    template <class charT, class Traits=std::char_traits<charT> >
    class MyOfstream : public std::basic_ofstream<charT,Traits> {
      public:
        MyOfstream(const char* name)
          : std::basic_ios<charT,Traits>(...streambufptr...),
           std::basic_ofstream<charT,Traits>(name) {}
         // ...
    };

The order of initialization would be:

1. `std::ios_base()`

2. `std::basic_ios (std::basic_streambuf*)`

3. `std::basic_ostream (const char*)`

4. `std::basic_ofstream (const char*)`

5. `MyOfstream (const char*)`

In other words, the constructor of `basic_ofstream` overwrites the stream buffer pointer set by the constructor of `basic_ios`.

To avoid this dilemma, class `basic_ios` has a protected default constructor in addition to its public constructor. This default constructor, which requires a stream buffer pointer, doesn't do anything. Instead, there is a protected initialization function `std::basic_ios<>::init()` that can be called by any class derived from `std::basic_ios<>`. With this function, initialization of the `std::basic_ios<>` base class is handled by the stream class that actually provides the stream buffer -- in our example, `std::basic_ofstream<>`. It calls the protected `init()` function:

    template <class charT, class Traits=std::char_traits<charT> >
    class MyOfstream : public std::basic_ofstream<charT,Traits> {
     public:
       MyOfstream(const char* name)
       : std::basic_ofstream<charT,Traits>(name) {}
       // ...
    };

The order of initialization is:

1. `std::ios_base()`

2. `std::basic_ios()`

3. std::basic_ostream (const char*)
   calls std::basic_ios::init(basic_streambuf*)

4. `std::basic_ofstream (const char*)`

5. `MyOfstream (const char*)`

### 38.3.2 Derivation from the Stream Classes std::basic_{i,o}stream

The scheme for deriving from the stream classes is slightly different in that you must always provide a pointer to a stream buffer. This is because the stream classes do not contain a stream buffer, as the file or string stream classes do. For example, a class derived from an output stream could look like this:

    template <class charT, class Traits = std::char_traits<charT> >
    class MyOstream : public std::basic_ostream<charT,Traits> {
      public:
        MyOstream(std::basic_streambuf<charT,Traits>* sb)
        : std::basic_ostream<charT,Traits>(sb) {}
        // ...
    };

There are several ways to provide the stream buffer required for constructing such a stream:

- Create the stream buffer independently, before the stream is created. Here is a simple example in which a file buffer is created as a separate object and used by the derived stream:

    std::filebuf strbuf;
    strbuf.open("/tmp/xxx");
    MyOstream<char> mostr(&strbuf);
    mostr << "Hello world\n";

- Take the stream buffer from another stream. In the example below, the stream buffer is "borrowed" from the standard error stream `std::cerr`:

    MyOstream<char,std::char_traits<char> >
      mostr(std::cerr.rdbuf());
    mostr << "Hello world\n";

Remember that the stream buffer is now shared between `mostr` and `cerr` (see Section 34.3 for details).

- Contain the stream buffer in the derived stream, either as a data member or inherited. It is typically preferred when a new stream buffer type is used along with the new stream type.