JLBorges wrote: |
---|
Their design goals are very different. In addition to an int there could be a user defined big_integer - should input/output of a big_integer be done in the same way as input/output of an int? |
I'm aware of that design goal, I agree that it's a good thing, and I'm glad that iostream accomplishes that much. But the way in which it accomplishes it is wretched, IMO.
The abuse of operator overloading, making the ostream have to operate like a state machine, and inconsistent memory of formatting flags is just a giant mess.
For example of the inconsistent memory thing...:
1 2 3 4 5
|
int v = 10;
cout << hex << setfill('0') << setw(3) << uppercase;
cout << v << endl;
cout << v << endl;
|
The output here is
Why is it that hex and uppercase are remembered, but setfill and setw are not? This is a really big gotcha that has bitten me several times.
JLBorges wrote: |
---|
Deriving from ostream is almost always a terribly convoluted design idea anyway. Streams are much easier to customize by using composition rather than inheritance. |
If you use composition and not inheritance, then your class will not work with the millions of lines of existing code that already use ostream.
The abstract concept of an ostream is very simple. It outputs a stream of bytes to something. The interface to derive from it should be equally simple. You should only have to implement a handful of basic, clear functions.
Something like this would make much more sense:
1 2 3 4 5 6 7 8
|
class ostream : blah blah
{
protected:
// implement these to derive from ostream
virtual size_t output(const char* buffer, size_t size) = 0;
virtual size_t tell() = 0;
virtual size_t seek() = 0;
};
|
Even a novice could write their own ostream with that kind of interface. And it could still be just as functional as the current ostream implementation.
JLBorges wrote: |
---|
The key design concept is the separation of formatting from buffering and physical device input/output - the former is handled by facets and manipulators, the latter by classes derived from std::streambuf. Customize stream behaviour by customizing streambuf, and if needed adding user-defined facets and manipulators. |
I have made several attempts to write my own streambuf class, even using copy-pasted examples. None of my attempts have been successful. Maybe it's because the examples I was using only worked with gcc and I was trying to compile them in VC++.
Whatever the reason, the examples were overly convoluted, confusing, and (for whatever reason)
didn't work.
Maybe the blame for them not working in this case belongs to one of the
compilers STL implementation for not being standards compliant. But that doesn't really change my main point which is that it is extremely difficult to do something that is conceptually simple, which, to me, just screams out "design flaw".
Of course, this is all better than printf, where the possibility of making your own FILE type or output device is entirely nonexistent.
Cubbi wrote: |
---|
I don't quite understand what can be described as "difficult or impossible" about deriving from ostream, though. |
Have you tried it? Were you successful?
If yes, I would love to see your code.