Re: concrete example on "inheriting" from ostream
AlfC ha scritto:
Since I wanted something that behaves almost like std::ofstream, the
original idea I had was to inherit from std::ofstream. Later I found,
the hard way, that it was a very very bad idea.
Really? I find that usually you don't need that and that there are
pitfalls you should avoid, but it's not a "very very bad" idea in general.
In fact, as you will see below, inheriting from std::ostream is not a
solution to your problems.
Looking in previous topics in the group I found that doing something
like this requires a more involved approach consisting in first
creating a class "custom_streambuf" that is derived from std::streambuf
and then creating the "custom_ofstream" class as privatelly derived
from custom_streambuf and publicly derived from ofstream. This is
described here
http://www.angelikalanger.com/Articles/C++Report/IOStreamsDerivation/IOStrea
msDerivation.html
You don't need all that! Those example probably tried to do a lot more
that you actually need, so you should not follow them to the letter. You
just need a formatter, right? So why bother about streambufs? Just
"borrow" one streambuf from another stream, like this:
class my_ostream : public std::ostream
{
public:
my_ostream(std::streambuf* buf) : std::ostream(buf)
{}
};
int main()
{
my_ostream my(std::cout.rdbuf());
// use my stream here!
}
Isn't that simple?
This question (or similar questions) had been around the group many
times however I didn't find a working code that reaches the point where
"friend operator<<(custom_ostream& , type const&)" or eventually member
"custom_ostream::operator<<(type const&)" is defined. Does any one have
a complete small working example of how to define output streams that
behaves much like a standard output stream except than *some* specific
types are printed in a different format?
There's only one little problem with this approach... the chaining of
operator<<! Consider the example above and add your pet formatter
function for complex<>
template <typename T>
my_stream& operator<<(my_stream& s, const std::complex<T>& c);
(or define it as a member of class my_stream, it doesn't matter). Now this:
my << std::complex<double>(3,4) << " " << 9 << std::endl;
will produce the output that you expect, but this one:
my << 9 << " " << std::complex<double>(3,4) << std::endl;
won't! Too bad. That's because the result of the subexpression 'my << 9
<< " "' is of type std::ostream& and not my_stream&. Overload doesn't
help you anymore!
Morale: an approach based on inheritance from std::ostream and overload
of operator<< is doomed to fail.
How to solve the problem then? You have several possibilities, among them:
1) use locales: define a custom facet for each way you want to output
your data and write one single overload of operator<< that delegates to
the facet. In this case you don't even need to define custom ostreams:
just imbue the correct locale in any stream and you're there. This
solution is the most extendable but also the most complex;
2) alternatively, you can use xalloc()/pword() to obtain a sort of "poor
man's" locale;
3) if you know in advance about all different ways of formatting a
certain type, you can write one (and only one) version of operator<<
that perform all kind of formatting and use xalloc()/iword() to select
among them.
I particular I am interested in the approach that uses "virtual
private" inheritance (which sounds very professional).
Are looking for a solution that actually works or you're just interested
in buzz-words? ;-)
Note that I still didn't ask yet about adding (or reusing standard)
manipulators, which is something that I will eventually need. Probably
an elegant solution will keep the old manipulators available for the
new custom output streams.
That's the last thing you need to bother about...
HTH,
Ganesh
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]