Introduction
This article shows an example of using C++ operator overloading to make a simple class that will accept fractions from the standard input and output them to the standard output.
It will also reduce (normalize) the entered fraction. The code is commented pretty heavily, so it should be pretty easy to follow.
This class is intended to be a sample of operator overloading, so it doesn't have a whole lot of functionality. My hope is that its simplicity will make it easy to understand.
What is operator overloading?
C++ only understands how to use operators (=
, <<
, >>
) on types it knows about such as int
, char
, long
, etc.
If you want to take advantage of these operators with your custom types then you will have to "overload" the operators you want to use with your custom type.
In this example I have overloaded the << and >> operators for writing to the standard input and output to accept fractions in the format n/d, n\d, or just plain n (n = numerator, d = denominator).
Overloading << and >>
If you take a look inside the Fraction.h header file you will see that we have told the compiler we want to overload both the <<
and >>
operators for CFraction
objects.
ostream& operator << (ostream& os, CFraction& fraction);
istream& operator >> (istream& is, CFraction& fraction);
Writing a fraction to stdout
Here is the function that handles the <<
operator. It takes care of formatting a CFraction
object and writing it to the standard output.
ostream& operator << (ostream& os, CFraction& fraction) {
os << fraction.GetNumerator();
os << '/';
os << fraction.GetDenominator();
return os;
}
Reading a fraction from stdin
istream& operator >> (istream& is, CFraction& fraction) {
char input[64];
is.getline(input, 64);
char *slash_pos = NULL;
slash_pos = strchr(input, '/');
if (slash_pos == NULL)
slash_pos = strchr(input, '\\');
if (slash_pos == NULL) {
if (strlen(input)) {
int numerator = atoi(input);
if (numerator) {
fraction.SetNumerator(numerator);
fraction.SetDenominator(1);
return is;
} else {
fraction.SetNumerator(0);
fraction.SetDenominator(0);
return is;
}
} else {
fraction.SetNumerator(0);
fraction.SetDenominator(0);
return is;
}
}
char str_numerator[32];
memcpy((void *)str_numerator, (void *)input, (slash_pos - input));
int numerator = 0;
numerator = atoi(str_numerator);
if (numerator) {
fraction.SetNumerator(numerator);
} else {
fraction.SetNumerator(0);
fraction.SetDenominator(0);
return is;
}
char str_denominator[32];
memcpy((void *)str_denominator, (void *)(slash_pos+1),
((input + strlen(input)) - slash_pos));
int denominator = 0;
denominator = atoi(str_denominator);
if (denominator) {
fraction.SetDenominator(denominator);
} else {
fraction.SetNumerator(0);
fraction.SetDenominator(0);
}
return is;
}
Sample Application
This is the source code for the sample console application that uses the class. It is very straightforward.
int main(void) {
CFraction *obj = new CFraction(2, 3);
cout << "Testing (2/3): \t\t";
cout << *obj << endl;
delete obj;
obj = new CFraction(4);
cout << "Testing (4): \t\t";
cout << *obj << endl;
delete obj;
obj = new CFraction();
cout << "Testing (no args): \t";
cout << *obj << endl << endl;
delete obj;
while(1) {
obj = new CFraction();
cout << "Enter a fraction (ctrl-c to exit): ";
cin >> *obj;
cout << endl << "You entered (before normalization): " << *obj;
obj->Normalize();
cout << endl << "You entered (after normalization): "
<< *obj << endl << endl;
delete obj;
}
}