|
-
May 8th, 2012, 06:09 PM
#1
Inherit from cout - how to override "<<" operator & forward to base
Using c++11, but I don't think that matters here.
output.displayHeader() must execute before the inherited from ostream (cout) executes streaming data, or bad things happen. It's of course not as simple as in the example below, and I need to make sure displayHeader() is never missed.
I'm thinking I need to override the "<<" operator, having my own function call displayHeader(), then call the base (cout) "<<" operator. What's the proper syntax for doing this?
I can't call displayHeader() in the constructor, and I can't call it right after the object is defined. There are exception case scenarios where displayHeader() must not be called, and other things must happen instead.
I'm aware this will result in many redundant bool comparisons versus the way I'm doing it now, and I'm perfectly OK with that.
Code:
#include <iostream>
using namespace std;
class myOutput : public ostream {
public:
myOutput() : ostream(cout.rdbuf()) {
}
void displayHeader() {
if(false == displayedHeader) {
*this << "HEADER" << endl;
displayedHeader = true;
}
}
private:
bool displayedHeader { false };
};
int main() {
myOutput output;
output.displayHeader(); // <-- I want this line to go away
output << "Hello" << endl; // <-- By having this line call displayHeader()
output << "Hello, again" << endl; // <-- and likewise this one, but it will see displayedHeader is true
}
Last edited by darlingm; May 8th, 2012 at 06:24 PM.
-
May 9th, 2012, 03:58 AM
#2
Re: Inherit from cout - how to override "<<" operator & forward to base
You can always define an operator<< for your myOutput, that just calls the displayheader, before forwarding to ostream<<:
Code:
#include <iostream>
using namespace std;
class toto
{ };
class myOutput : public ostream {
public:
myOutput()
: ostream(cout.rdbuf())
, displayedHeader(false)
{ }
void displayHeader()
{
if(false == displayedHeader)
{
*this << "HEADER" << endl;
displayedHeader = true;
}
}
private:
bool displayedHeader;
};
template <typename T>
myOutput& operator<<(myOutput& myo, const T& v)
{
myo.displayHeader();
static_cast<std::ostream&>(myo) << v;
return myo;
}
int main() {
myOutput output;
//output.displayHeader(); // <-- I want this line to go away
output << "Hello" << endl; // <-- By having this line call displayHeader()
output << "Hello, again" << endl; // <-- and likewise this one, but it will see displayedHeader is true
}
I'm not 100% sure of the impact afterwards for user writen ostream operators, but I think it should be fine.
Is your question related to IO?
Read this C++ FAQ article at parashift by Marshall Cline. In particular points 1-6.
It will explain how to correctly deal with IO, how to validate input, and why you shouldn't count on "while(!in.eof())". And it always makes for excellent reading.
-
May 9th, 2012, 08:55 PM
#3
Re: Inherit from cout - how to override "<<" operator & forward to base
 Originally Posted by monarch_dodra
You can always define an operator<< for your myOutput, that just calls the displayheader, before forwarding to ostream<<:
. . .
I'm not 100% sure of the impact afterwards for user writen ostream operators, but I think it should be fine.
Awesome, thanks! This seems to work well.
I'd also like to make displayHeader() a private function, but it isn't critical, and I can live without it. Is there an easy way to do so? The following code repeatedly runs displayHeader() on my system, deciding that displayedHeader is always false, until the program runs out of memory/hits its maximum allowed memory size. (Without the added red template/friend lines in the class, it runs flawlessly.) I'm assuming I must be triggering an object copy so the original bool is never modified, or something like that, although I can't imagine why it's doing this.
I realize I left displayHeader() public in my example, just wanted to illustrate that adding two lines by themselves caused the issue.
I'm pretty sure the cause is that I don't understand something related to template friend functions, so I doubt the compiler has anything to do with it, but I do run a SVN source build of gcc to keep up with their c++11 implementation. EDIT: Recompiled using system's original gcc 4.1.2, and had the same unexpected behavior.
Code:
#include <iostream>
using namespace std;
class myOutput : public ostream {
public:
myOutput()
: ostream(cout.rdbuf())
, displayedHeader(false)
{ }
void displayHeader()
{
if(false == displayedHeader)
{
*this << "HEADER" << endl;
displayedHeader = true;
}
}
template <typename T>
friend myOutput& operator<<(myOutput& myo, const T& v);
private:
bool displayedHeader;
};
template <typename T>
myOutput& operator<<(myOutput& myo, const T& v)
{
myo.displayHeader();
static_cast<std::ostream&>(myo) << v;
return myo;
}
int main() {
myOutput output;
//output.displayHeader(); // <-- I want this line to go away
output << "Hello" << endl; // <-- By having this line call displayHeader()
output << "Hello, again" << endl; // <-- and likewise this one, but it will see displayedHeader is true
}
Last edited by darlingm; May 9th, 2012 at 08:59 PM.
-
May 10th, 2012, 04:11 AM
#4
Re: Inherit from cout - how to override "<<" operator & forward to base
 Originally Posted by darlingm
Code:
void displayHeader()
{
if(false == displayedHeader)
{
*this << "HEADER" << endl;
displayedHeader = true;
}
}
The line in red: This will actually call your template operator<<, which will call displayedHeader, which will call...
There are 2 ways to solve this:
1) The wrong way: Move "displayedHeader = true;" to the line above, this way, the second time you enter it, it breaks the recursive calls.
2) Make an explicit call to ostream's operator<< by casting to ostream:
Code:
void displayHeader()
{
if(false == displayedHeader)
{
static_cast<ostream&>(*this) << "HEADER" << endl;
displayedHeader = true;
}
}
The difference in behavior comes from the fact that in the previous example, the implementation did not "know" about the template.The friend declaration also forward declared it, so that is why it got called.
Had you forward declared the template, or implemented the "displayHeader" in a later .cpp, you would have seen the same behavior.
Is your question related to IO?
Read this C++ FAQ article at parashift by Marshall Cline. In particular points 1-6.
It will explain how to correctly deal with IO, how to validate input, and why you shouldn't count on "while(!in.eof())". And it always makes for excellent reading.
-
May 10th, 2012, 04:47 AM
#5
Re: Inherit from cout - how to override "<<" operator & forward to base
 Originally Posted by darlingm
I'm thinking I need to override the "<<" operator, having my own function call displayHeader(), then call the base (cout) "<<" operator.
I think you should reconsider your design as you're using public inheritance the wrong way; consider what happens when you invoke a function taking an ostream& ( like ostream_iterator ctor, for example ... ): your operator<< won't be called breaking your invariants.
You should rewrite your design by overriding the virtual protected interface of streambuf instead.
-
May 10th, 2012, 06:25 AM
#6
Re: Inherit from cout - how to override "<<" operator & forward to base
 Originally Posted by superbonzo
I think you should reconsider your design as you're using public inheritance the wrong way; consider what happens when you invoke a function taking an ostream& ( like ostream_iterator ctor, for example ... ): your operator<< won't be called breaking your invariants.
You should rewrite your design by overriding the virtual protected interface of streambuf instead.
Very true. I knew there was something fishy somewhere with my approach...
----
To the OP: I think you may want to look into:
http://www.cplusplus.com/reference/iostream/streambuf/
And in particular:
http://www.cplusplus.com/reference/i...eambuf/xsputn/
Is your question related to IO?
Read this C++ FAQ article at parashift by Marshall Cline. In particular points 1-6.
It will explain how to correctly deal with IO, how to validate input, and why you shouldn't count on "while(!in.eof())". And it always makes for excellent reading.
Posting Permissions
- You may not post new threads
- You may not post replies
- You may not post attachments
- You may not edit your posts
-
Forum Rules
|
Click Here to Expand Forum to Full Width
|