C++ allows a programmer to overload operators such as the arithmetic or comparison operators. This allows a programmer to use these operators in a very natural way with objects of classes that he / she has created. For example:
MyClass a; MyClass b; // Assign values to objects a and b MyClass c; c = a - b; //assign c the result of subtracting b from a
In this lab you will overload the arithmetic operators (+, -, *, /) for a Fraction class. The Fraction class (without the overloaded operators) is provided below.
To write an overloaded operator you need to define the operator in the .h file, and write the implementation in the .cpp file, just like any other class method. Here is the header file entry for the fraction + operator:Fraction operator+(const Fraction & f) const;
And here is a stub for the implementation file entry:
Fraction Fraction::operator+ (const Fraction& f) const { Fraction result; // Calculate result here ... return result; }
Note that implementing the + operator involves 3 fractions, the one on the left of the operator, the one on the right, and the one that results from adding the two together (the return value). Consider adding two fractions, x and y, and assigning their result to a third fraction, z:
z = x + y;
The return value is assigned to z, but is x the calling object (the one that the overloaded operator "belongs to") or the parameter? This doesn't really matter much for the + operator but it will matter for the - and / operators and for other operators such as some of the comparison operators (which you will need for assignment 3). The answer is that the calling object is the left hand operand (x in this example).
Finally, note the use of the const keyword in the function header. Both the calling object and the parameter are declared as constant (the const that follows the parameter list declares the calling object as constant).
This tutorial covers the cout
<< operator. Please read it carefully and follow along by
running the given code. You should modify test_cout.cpp and use it as
the driver program for doing so.
The driver program can be built by running "make test_cout", and run
by "./test_cout"
It is often useful to overload the cout << operator, so that you can print an object like this:
Fraction f(2,3); cout << f; //which should print something like 2/3
Achieving this is a little more complicated than the process shown previously. There are a couple of reasons for this. The first is that the cout << operator is itself an overloaded operator (overloaded by the ostream class). In theory we could get access to iostream.h and mess around with it so that cout recognized Fractions but this is not a good idea. Instead we will write a function that overloads the operator for the Fraction class.
The header file entry looks like this:friend void operator<<(ostream & os, const Fraction & f);
You'll notice the keyword friend here. This means that the function is designated as a friend of the Fraction class and so has access to its private attributes. Note that the function is not a member of the Fraction class, so when you implement it in the .cpp file you shouldn't precede it with Fraction::.
A reasonable implementation would look like this:
void operator<<(ostream & os, const Fraction & f){ os << f.numerator << "/" << f.denominator; }
As noted above this is not a member of the Fraction class, but because the function is a friend of the class, it can access its private members. Note that in cout << f; the first parameter (ostream & os) is matched to the left operand, and the second parameter (Fraction & f) is matched to the right operand.
Try outputting a fraction using cout, it should work OK. Unfortunately, it really isn't good enough as you can see if you put this line of code in your test program:
Fraction f(3, 4); cout << f << " is a fraction!";
You will get a compilation error. Why? (That's a rhetorical question.)
The << is a binary operator (it takes two operands) and the cout statement above is read from left to right so is actually equivalent to:
(cout << f) << " is a fraction!";
Our operator << function is void (it doesn't return anything) so that is equivalent to:
void << " is a fraction!"; //illegal operands compilation errors
So we need to return an ostream object to be used as the left operand for the << operator. So the final version should look like this:
ostream & operator<<(ostream & os, const Fraction & f){ os << f.numerator << "/" << f.denominator; return os; }
Don't forget to change the return type in the header file as well.
Now test it to make sure that it works!
The code for the fraction class that you should complete is provided in the zipfile (Fraction.h, Fraction.cpp). The .cpp file includes a reminder (in comments) of how you would go about implementing the arithmetic operators.
Complete the +,-,/,* operators. You can build the test executables by typing "make." They can be automatically tested by following the instructions below.
There is also a test script (again test.py), which you can run. If you have correctly built executables that solve this lab you will see:
uname@hostname: ~$ make g++ -Wall -c test_add.cpp g++ -Wall -c Fraction.cpp g++ -Wall -o test_add test_add.o Fraction.o g++ -Wall -c test_sub.cpp g++ -Wall -o test_sub test_sub.o Fraction.o g++ -Wall -c test_mult.cpp g++ -Wall -o test_mult test_mult.o Fraction.o g++ -Wall -c test_div.cpp g++ -Wall -o test_div test_div.o Fraction.o g++ -Wall -c test_cout.cpp g++ -Wall -o test_cout test_cout.o Fraction.o uname@hostname: ~$ ./test.py Running test add... passed Running test sub... passed Running test mult... passed Running test div... passed Passed 4 of 4 tests.
If you have passed at least 2 of 4 tests, please ask a TA to take a look at this output, and receive your 1 mark for this lab.