Creating own IO streams

M

Martin Magnusson

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?
 
K

Karl Heinz Buchegger

Martin said:
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.
 
S

Siemel Naran

Martin Magnusson said:
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.
 
M

Martin Magnusson

Karl Heinz Buchegger said:
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;
}
 
J

John Harrison

Martin Magnusson said:
Karl Heinz Buchegger said:
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
 
K

Karl Heinz Buchegger

Martin said:
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.
 
D

Dietmar Kuehl

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...
 

Ask a Question

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

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,744
Messages
2,569,479
Members
44,900
Latest member
Nell636132

Latest Threads

Top