[try Beta version]
Not logged in

 
Overloading a derived class operator

Oct 19, 2016 at 9:01pm
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...
Oct 19, 2016 at 9:29pm
You need to show your code, you should be able to overload different overloads for the different streams.

Oct 19, 2016 at 9:36pm
Keep in mind that operator<< returns a reference to an ostream not an fstream so chaining may be problematic.
Oct 19, 2016 at 9:44pm
But you can overload the operator<< for an fstream that returns a reference to an fstream and it should work.
Oct 20, 2016 at 6:51am
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.
Oct 20, 2016 at 7:10am
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;
}


Oct 20, 2016 at 8:21am
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();
}


Oct 20, 2016 at 8:35am
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 Oct 20, 2016 at 8:36am
Oct 20, 2016 at 8:41am
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 Oct 20, 2016 at 8:48am
Oct 20, 2016 at 9:02am
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?
Oct 20, 2016 at 12:12pm
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.
Oct 20, 2016 at 1:31pm
Thanks you helped me a lot!

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