Overloading a derived class operator

Hi,

It is either a stupid question or a normal question, but I'll ask it anyway:

Is there a way to overload a << operator differently for ostream and fstream?

I tried to do it and it compiled, although it output to my file according to the ostream overload and not the fstream one...
You need to show your code, you should be able to overload different overloads for the different streams.

Keep in mind that operator<< returns a reference to an ostream not an fstream so chaining may be problematic.
But you can overload the operator<< for an fstream that returns a reference to an fstream and it should work.
My code goes something like:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
ostream & operator<<(ostream&os, MyClass& mc)

{
     //overloading...
return os;
}

fstream & operator<<(fstream&fs, MyClass& mc)

{
     //overloading...
return fs;
}

MyClass mc;
fstream file("something.txt", ios_base::out);
file<<mc;



And then it outputs as I overloaded the ostream, the fstream overload is ignored.
The following worked for me:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
#include <iostream>
#include <fstream>

struct Check
{
    int value;
};

std::fstream& operator<<(std::fstream& out, const Check& c)
{
    out << " FSTREAM " << c.value;
    return out;
}

std::ostream& operator<<(std::ostream& out, const Check& c)
{
    out << " OSTREAM " << c.value;
    return out;
}

int main()
{
    Check c;
    c.value = 10;

    std::cout << c << std::endl;  // Uses the ostream overload.

    std::fstream fout("test.data", std::ios::out | std::ios::app);
    if(!fout)
        std::cerr << "Failed to open the file!\n";

    fout << c << std::endl;  // Uses the fstream overload.

    std::ofstream tout("test.dat");
    if(!tout)
        std::cerr << "Failed to open the file!\n";

    tout << c << std::endl; // Uses the ostream overload.

    return 0;
}


But you can overload the operator<< for an fstream that returns a reference to an fstream and it should work.

Or a reference to an ofstream if you're using one of those... either way, chaining is problematic. See the code below (modified to use a string stream rather than a file stream to simplify things:)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#include <iostream>
#include <sstream>

struct Check { int value; };

std::ostringstream& operator<<(std::ostringstream& out, const Check& c){
    out << " ostringstream " << c.value;
    return out;
}

std::ostream& operator<<(std::ostream& out, const Check& c) {
    return out << " ostream " << c.value;
}

int main(){
    Check c { 10 };

    std::ostringstream os;
    os << c << '\n' << c << '\n';           // ostringstream overload followed by ostream overload.

    std::cout << os.str();
}


I tried your code and it runs fine... There must be something wrong with my code, and it's strange because its structured the same way...

Now I have another question concerning overload. I wrote this code and it didn't compile:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

fstream & operator << (fstream&fs, lib& l)

{
	fs << '{';
	for (Book b : l.booklist)
	{
        fs << 'B';
	fs << b;
}
	for (User u : l.userlist)
{
		fs << 'U'<<u;
}

	fs << '}';
	return fs;
}


Notice the bold part. It gives me an error: "binary '<<': no operator found which takes a right-hand operand of type 'User' (or there is no acceptable conversion)"

Although I overloaded my user just fine. But if I split the output like this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
fstream & operator << (fstream&fs, lib& l)

{
	fs << '{';
	for (Book b : l.booklist)
	{
        fs << 'B';
	fs << b;
}
	for (User u : l.userlist)
{
		fs << 'U';
		fs << u;
}

	fs << '}';
	return fs;
}


It compiles, runs, and gives the output defined in the User overload just fine.
Any idead why?
Last edited on
It compiles, runs, and gives the output defined in the User overload just fine.
Any idead why?

See the post directly above your last one. Chaining is problematic. The only time your overload will be used is if it is the first item in the chain (or follows the first x items which also use your overload in the chain.)

fs << 'U'<<u;
is equivalent to:

1
2
    auto retVal = fs << 'U';  // where the retVal is a std::ostream&
    retval << u; // so the ostream overload is called here.  

Last edited on
I see.
Then why does the ostream overload persists through the whole stream and the derived classes overload does not? Is there a way to tell it not to?
Your overload persists, but you don't have an overload for fstream& operator>>(fstream&, char), which would be required for the code to work since you use the return value from that function call to feed the next in the chain of calls. As you can imagine, exhaustively defining all possible overloads isn't something you want to do. You can get around this with a little template magic, but then you're suddenly changing potential behavior for all interactions with different stream types which is a mess of its own.

Don't try to subvert the system to do something it was designed not to do. Streams are generic so that you can treat them all the same. Your point of customization should be supplied by the class itself as a member function or as a stand-alone function that returns a string that can be fed to your stream or possibly a wrapper type that will define the correct behavior.
Thanks you helped me a lot!

Have a nice day
Topic archived. No new replies allowed.