Understanding on Overloading >>

I am starting a new function and my book has a very limited example to go on. Furthermore, there are no examples to go on from my class. I have to create an overloaded >> function that can read in fractional values. Their forms will have negatives in the numerator, improper fractions will be read as 5/2 -> 2+1/2. Note that the + is for and so it reads 2 and 1/2, and if a negative mixed number then the negative is with the whole number part. I need some direction as to how this works so I can begin to apply my own logic.

This is what I have started with and I get this error:
error C2678: binary '<<': no operator found which takes a left-hand operand of type 'std::istream' (or there is no acceptable conversion)

1
2
3
4
5
6
 std::istream& operator >> (std::istream& strm, Fraction& right)
	{
		cin >> right.numerator;

		return strm;
	}
Last edited on
Your error says <<, but your code example shows >>, I think you're getting the arrow direction mixed up.

A nice way to remember is that the stream object is always on the left, but the >> and << point in the direction the information is going.

so you do:
1
2
cin >> a; // information goes from cin to a;
cout << a; // information goes from a to cout; 


What are the properties of your Fraction class? Fraction.numerator and Fraction.denominator?

You should be doing something closer to this instead:

1
2
3
4
5
6
7
std::istream& operator >> (std::istream& strm, Fraction& right)
	{
		strm >> right.numerator;
                strm >> right.denominator;

		return strm;
	}


What exactly do you want the user to be able to type?
Do you want the user to be able to type "2 3" to means "2/3"?
If you want the user to be able to type "2/3" with the slash, you'd want something like:
1
2
3
4
5
6
7
8
9
std::istream& operator >> (std::istream& strm, Fraction& right)
{
	strm >> right.numerator;
	char slash;
	strm >> slash;
        strm >> right.denominator;

	return strm;
}


Call it like:
1
2
Fraction fraction; // default ctor
std::cin >> fraction;
Last edited on
Thank you, that all helps to fill in the banks. I started doing some tests on it and I can take user input numerator/denominator and it produces the right output with some tests and the wrong output with some other tests. I am trying to understand why so I can address the issue.

Output that works good:

Enter a numerator/denominator: 5/2
2+1/2
Enter a numerator/denominator: 1/2
1/2
Enter a numerator/denominator: -1/2
-1/2


Output that does not work good:

Enter a numerator/denominator: 5/-2
-2+1/-2
Enter a numerator/denominator: 1/-2
0+1/-2
Enter a numerator/denominator: -1/-2
0+-1/-2

I have defined my overloaded << function so that it outputs all these examples correctly from fraction objects with hard coded parameters, but when I use the cin >> fraction object from user input in main then then some are wrong.

Here, I get an error with the red squiggly line under the first >> in the if statement. Same error as above.

1
2
3
4
5
6
7
8
9
10
11
12
13

std::istream& operator >> (std::istream& strm, Fraction& right)
	{
		char slash;
		int numerator, denominator;
		strm >> right.numerator >> slash >> right.denominator;

		if (right.numerator < 0 && right.denominator < 0) {
			strm >> abs(right.numerator) >> slash >> abs(right.denominator);
		}
		
		return strm;
	}
Last edited on
You should post what the actual error given to you is.
The error I get is
9:9: error: ambiguous overload for 'operator>>' (operand types are 'std::istream {aka std::basic_istream<char>}' and 'int')


Two issues:
(1) You define local numerator and denominator variables, but never use them. Just remove line 5.

(2) I admit the error message isn't too clear concerning the root issue, but the problem is you are trying to use your input to put a value into a temporary value, abs(right.numerator). Only actual variables can be references, not temp values. You already called strm >> to get the numerator and denominator on line 6; you don't want to call strm >> more times than necessary within the operator overload function, because that makes the user have to re-type things in.

Perhaps something this like would be better, always keeping the denominator positive for consistency.
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
// Example program
#include <iostream>
#include <string>

struct Fraction {
    int numerator;
    int denominator;
};

std::istream& operator >> (std::istream& strm, Fraction& right)
{
	char slash;

	strm >> right.numerator >> slash >> right.denominator;
	
	if (right.denominator < 0)
	{
	    right.denominator = -right.denominator;
	    right.numerator = -right.numerator;
	}
	
	return strm;
}

std::ostream& operator << (std::ostream& os, const Fraction& right)
{
    return os << right.numerator << '/' << right.denominator << '\n';   
}
	
int main()
{
    using std::cin;
    using std::cout;
    
    Fraction f;
    cout << "Enter fraction: ";
    cin >> f;
    
    cout << f << '\n';
}


Enter fraction: -4/3
-4/3


Enter fraction: 4/-3
-4/3


Enter fraction: -4/-3
4/3


From there, you can do the necessary math to split the fraction up.
Last edited on
I am starting to get a better feel for how it works. It's not the cleanest looking code but it seems to work. If anyone has some ideas to make it more efficient I would like to learn how to improve my code.

Thank you


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
std::istream& operator >> (std::istream& strm, Fraction& right)
	{
		char fractionBar;

		strm >> right.numerator >> fractionBar >> right.denominator;
		
		if ((right.numerator % right.denominator == 0) && right.denominator < 0 ) { // 8/-2  now show as -4. Before this code was showing -4+0/2
			
			right.numerator = (right.numerator / right.denominator) * 1;
			right.denominator = 1;
		}
		if (right.numerator > 0 && right.denominator < 0) { // move '-' to numerator

			right.numerator = right.numerator * -1;
			right.denominator = right.denominator * -1;
			
				if (right.numerator / right.denominator == 1) { // got rid of fractional 1 values such as 5/5. Now showing 1
					right.numerator = 1;
					right.denominator = 1;
				}
			
		}
		if (right.numerator < 0 && right.denominator < 0) { // double -/- to positive
			
			right.denominator = -right.denominator;
			right.numerator = -right.numerator;
		}
		if(right.numerator % right.denominator == 0) { // give whole # for even divides

			right.numerator = right.numerator / right.denominator;
			right.denominator = 1;

		}
		return strm;
	}
Topic archived. No new replies allowed.