As an example of a numeric class, consider a class called Fraction, which stores a number as the ratio of two long integers. This is useful because many numbers cannot be expressed exactly in floating-point notation. For example, the quantity 1/3 is represented as 0.33333. The expression 1/3 + 1/3 + 1/3 should add up to 1, but instead it adds up to 0.99999. Over the course of a lengthy calculation, this type of error is cumulative and can become quite significant. A Fraction class removes this type of error.
To add two Fraction objects, you can overload the + operator as follows:
// Overloading the + operator
#include <stdlib.h>
#include <math.h>
#include <iostream.h>
class Fraction
{
public:
Fraction();
Fraction( long num, long den );
void display() const;
Fraction operator+( const Fraction &second ) const;
private:
static long gcf( long first, long second );
long numerator,
denominator;
};
// ----------- Default constructor
Fraction::Fraction()
{
numerator = 0;
denominator = 1;
}
// ----------- Constructor
Fraction::Fraction( long num, long den )
{
int factor;
if( den == 0 )
den = 1;
numerator = num;
denominator = den;
if( den < 0 )
{
numerator = -numerator;
denominator = -denominator;
}
factor = gcf( num, den );
if( factor > 1 )
{
numerator /= factor;
denominator /= factor;
}
}
// ----------- Function to print a Fraction
void Fraction::display() const
{
cout << numerator << '/' << denominator;
}
// ----------- Overloaded + operator
Fraction Fraction::operator+( const Fraction &second ) const
{
long factor,
mult1,
mult2;
factor = gcf( denominator, second.denominator );
mult1 = denominator / factor;
mult2 = second.denominator / factor;
return Fraction( numerator * mult2 + second.numerator * mult1,
denominator * mult2 );
}
// ----------- Greatest common factor
// computed using iterative version of Euclid's algorithm
long Fraction::gcf( long first, long second )
{
int temp;
first = labs( first );
second = labs( second );
while( second > 0 )
{
temp = first % second;
first = second;
second = temp;
}
return first;
}
A Fraction object is declared with two integers, the numerator and the denominator. The constructor checks that the denominator is nonzero and nonnegative, and simplifies the fraction if possible. The class defines a private static function named gcf to calculate the greatest common factor of two numbers.
The following program uses the Fraction class and demonstrates the use of the overloaded + operator.
void main()
{
Fraction a,
b( 23, 11 ),
c( 2, 3 );
a = b + c;
a.display();
cout << '\n';
}
The expression b + c is interpreted as b.operator+( c ). The operator+ function is called for the b object, using c as a parameter.
An overloaded operator doesn't have to have objects for both operands. You can add a Fraction and an integer as well by writing another function:
Fraction Fraction::operator+( long second ) const
{
return Fraction( numerator + second * denominator,
denominator );
}
This permits statements like the following:
void main()
{
Fraction a,
b( 2, 3 );
a = b + 1234;
}
However, you cannot write a statement like this:
a = 1234 + b; // Error
Since operator+ is defined as a member function, the previous statement is interpreted as follows:
a = (1234).operator+( b ); // Error
This statement is clearly an error, since an integer doesn't have a member function that can be invoked to perform the addition.
To allow expressions where a variable of a built-in type is the first operand, you must use friend functions (described in Chapter 6).