Creating own IO streams

Discussion in 'C++' started by Martin Magnusson, Jun 15, 2004.

  1. I'd like to create my own output streams, in order to be able to
    redirect output strings to a console, a status window or whatever,
    depending on the environment. For example, IO::warning << "Bad stuff";
    could output a string on stderr to start with, and when I have written
    a nice GUI, it could be output to a status window or a log file or
    something.

    I have written a skeleton file which looks like this:

    //---------------------
    #include <iostream>
    #include <string>

    namespace IO
    {
    template <class charT, class Traits=std::char_traits<charT> >
    class My_Ostream : public std::basic_ostream< charT, Traits >
    {
    public:
    My_Ostream( std::basic_streambuf< charT, Traits >* sb =
    std::cerr.rdbuf())
    : std::basic_ostream< charT, Traits >( sb )
    {
    its_sb = sb;
    }

    std::basic_ostream<charT, Traits>& operator <<
    ( charT& input )
    {
    its_sb << "[" << input << "]";
    }

    private:
    std::basic_streambuf< charT, Traits >* its_sb;
    };

    // IO::warning is just std::cerr.
    My_Ostream< char, std::char_traits<char> > warning(
    std::cerr.rdbuf() );

    }
    //---------------------

    When calling
    IO::warning << "Yo";
    I'm expecting the output "[Yo]" on cerr, but I'm just getting "Yo".

    Can anybody help me with a proper definition of the << operator?
    Martin Magnusson, Jun 15, 2004
    #1
    1. Advertising

  2. Martin Magnusson wrote:
    >
    > I'd like to create my own output streams, in order to be able to
    > redirect output strings to a console, a status window or whatever,
    > depending on the environment. For example, IO::warning << "Bad stuff";
    > could output a string on stderr to start with, and when I have written
    > a nice GUI, it could be output to a status window or a log file or
    > something.


    Your attempt is flawed.
    Instead of writing a new stream class you should configure
    an ordinary ostream object to do what you want. You do this
    by writing a new streambuf class and tell the ostream object
    to use that instead of the one it has.

    Search this group or the web for postings of 'Dietmar Kuehl'. He
    has shown a number of times how this is done.

    --
    Karl Heinz Buchegger
    Karl Heinz Buchegger, Jun 15, 2004
    #2
    1. Advertising

  3. Martin Magnusson

    Siemel Naran Guest

    "Martin Magnusson" <> wrote in message

    > template <class charT, class Traits=std::char_traits<charT> >
    > class My_Ostream : public std::basic_ostream< charT, Traits >
    > {
    > public:
    > My_Ostream( std::basic_streambuf< charT, Traits >* sb =
    > std::cerr.rdbuf())
    > : std::basic_ostream< charT, Traits >( sb )
    > {
    > its_sb = sb;
    > }
    >
    > std::basic_ostream<charT, Traits>& operator <<
    > ( charT& input )
    > {
    > its_sb << "[" << input << "]";
    > }
    >
    > private:
    > std::basic_streambuf< charT, Traits >* its_sb;
    > };


    You should not override non-virtual function. You override operator<<(char)
    but your call to stream << "yo" looks for operator<<(const char *) and
    therefore calls the base class version.

    In your approach, don't use public inheritance. Also, provide a template
    operator<< function. Consider renaming output argument 'input' too :).

    template <class T>
    std::basic_ostream<charT, Traits>& operator <<
    ( const T& object)
    {
    its_sb << "[" << object << "]";
    }

    But its_sb has to be a pointer or reference to a stream, not a streambuf or
    pointer to one.

    You should also research the streambuf method suggested by Karl, namely
    overriding overflow.

    Both solutions have been posted to these newsgroups and
    comp.lang.c++.moderated.
    Siemel Naran, Jun 15, 2004
    #3
  4. Karl Heinz Buchegger <> wrote:
    > Search this group or the web for postings of 'Dietmar Kuehl'. He
    > has shown a number of times how this is done.


    I did that, and tried to implement one of the examples posted at his
    web site. There seems to be a problem with inheritance that I don't
    quite understand, though. I get the following message, both with g++
    and Dev-C++:

    /usr/include/c++/3.3.1/streambuf: In member function `virtual int
    Prefixed_Stream_Buffer::sync()':
    /usr/include/c++/3.3.1/streambuf:749: error: `int
    std::basic_streambuf<_CharT, _Traits>::sync() [with _CharT = char,
    _Traits = std::char_traits<char>]' is protected
    IO.cpp:40: error: within this context

    The relevant code looks like this:

    #include <iostream>

    class Prefixed_Stream_Buffer: public std::streambuf
    {
    public:
    Prefixed_Stream_Buffer( std::streambuf *sb, const char* prefix );

    protected:
    int overflow( int c );
    int sync();

    private:
    std::streambuf *its_sb;
    const char* its_prefix;
    int its_prefix_length;
    bool it_has_pending_newline;
    };

    int Prefixed_Stream_Buffer::sync()
    {
    its_sb->sync(); // ERROR HERE (LINE 40)
    return 0;
    }
    Martin Magnusson, Jun 16, 2004
    #4
  5. "Martin Magnusson" <> wrote in message
    news:...
    > Karl Heinz Buchegger <> wrote:
    > > Search this group or the web for postings of 'Dietmar Kuehl'. He
    > > has shown a number of times how this is done.

    >
    > I did that, and tried to implement one of the examples posted at his
    > web site. There seems to be a problem with inheritance that I don't
    > quite understand, though. I get the following message, both with g++
    > and Dev-C++:
    >
    > /usr/include/c++/3.3.1/streambuf: In member function `virtual int
    > Prefixed_Stream_Buffer::sync()':
    > /usr/include/c++/3.3.1/streambuf:749: error: `int
    > std::basic_streambuf<_CharT, _Traits>::sync() [with _CharT = char,
    > _Traits = std::char_traits<char>]' is protected
    > IO.cpp:40: error: within this context
    >
    > The relevant code looks like this:
    >
    > #include <iostream>
    >
    > class Prefixed_Stream_Buffer: public std::streambuf
    > {
    > public:
    > Prefixed_Stream_Buffer( std::streambuf *sb, const char* prefix );
    >
    > protected:
    > int overflow( int c );
    > int sync();
    >
    > private:
    > std::streambuf *its_sb;
    > const char* its_prefix;
    > int its_prefix_length;
    > bool it_has_pending_newline;
    > };
    >
    > int Prefixed_Stream_Buffer::sync()
    > {
    > its_sb->sync(); // ERROR HERE (LINE 40)
    > return 0;
    > }


    Right sync is protected so you cannot access it through a pointer like that,
    the fact that you are in a method of a class derived from streambuf is
    irrelevant, many people don't understand this.

    Use the public version of sync instead, called pubsync.

    int Prefixed_Stream_Buffer::sync()
    {
    return its_sb->pubsync();
    }

    john
    John Harrison, Jun 16, 2004
    #5
  6. Martin Magnusson wrote:
    >
    > Karl Heinz Buchegger <> wrote:
    > > Search this group or the web for postings of 'Dietmar Kuehl'. He
    > > has shown a number of times how this is done.

    >
    > I did that, and tried to implement one of the examples posted at his
    > web site. There seems to be a problem with inheritance that I don't
    > quite understand, though. I get the following message, both with g++
    > and Dev-C++:
    >


    mail Dietmar directly.
    His mail address is given on the web site.

    --
    Karl Heinz Buchegger
    Karl Heinz Buchegger, Jun 16, 2004
    #6
  7. (Martin Magnusson) wrote:
    > I did that, and tried to implement one of the examples posted at his
    > web site. There seems to be a problem with inheritance that I don't
    > quite understand, though. I get the following message, both with g++
    > and Dev-C++:
    >
    > /usr/include/c++/3.3.1/streambuf: In member function `virtual int
    > Prefixed_Stream_Buffer::sync()':
    > /usr/include/c++/3.3.1/streambuf:749: error: `int
    > std::basic_streambuf<_CharT, _Traits>::sync() [with _CharT = char,
    > _Traits = std::char_traits<char>]' is protected
    > IO.cpp:40: error: within this context


    This error message just says that 'sync()' cannot be called from outside
    the object, not even from another class also derived from 'std::streambuf'
    (this is due to the way protected members work). Actually, the 'sync()'
    method was public in the IOStreams prior to standardization. It was turned
    into two functions, 'sync()' and 'pubsync()', with the former being virtual
    and protected and the latter being public and non-virtual. 'pubsync()'
    merely forwards the request to 'sync()'. Thus, this problem should be easy
    to fix:

    > int Prefixed_Stream_Buffer::sync()
    > {
    > its_sb->sync(); // ERROR HERE (LINE 40)


    Just replace the above line by

    its_sb->pubsync();

    > return 0;
    > }


    The code at the website is somewhat aged by now and is mostly written to
    prestandard libraries. I haven't come around to updating it and this task
    is also not really high on my priority list...
    --
    <mailto:> <http://www.dietmar-kuehl.de/>
    <http://www.contendix.com> - Software Development & Consulting
    Dietmar Kuehl, Jun 16, 2004
    #7
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Stefan Siegl
    Replies:
    1
    Views:
    754
  2. Lasse Skyum

    my own streams

    Lasse Skyum, Oct 23, 2003, in forum: C++
    Replies:
    7
    Views:
    484
    Micah Cowan
    Oct 25, 2003
  3. Saverio M.
    Replies:
    0
    Views:
    496
    Saverio M.
    Jul 3, 2006
  4. =?UTF-8?B?UmFmYcWCIE1haiBSYWYyNTY=?=

    Own filters(?) to streams

    =?UTF-8?B?UmFmYcWCIE1haiBSYWYyNTY=?=, Feb 16, 2006, in forum: C++
    Replies:
    4
    Views:
    347
  5. David Filmer
    Replies:
    17
    Views:
    246
    J. Romano
    Aug 18, 2004
Loading...

Share This Page