Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Using C++ operator overloading to make a simple fraction class

0.00/5 (No votes)
9 May 2003 2  
Shows a sample of operator overloading in C++

Sample Image - CFraction.jpg

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.

// Overloading of the iostream << and >> operators

// These must be declared ouside our class, with global scope


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.

// Overloaded iostream << operator

//

// When the << operator is called with a CFraction on 

// the right our overloaded function is called. We

// are passed a reference to the stream and the CFraction 

// to the right. We are free to output to the

// stream anthing we want as a result.

//

// We return the ostream& so that we can put multiple

// << operations on a single line


ostream& operator << (ostream& os, CFraction& fraction) {

 // Output the fraction to the stream in the format n/d 

 os << fraction.GetNumerator();
 os << '/';
 os << fraction.GetDenominator();

 return os;


}

Reading a fraction from stdin

// Overloaded iostream >> operator

//

// I tried to write this so it is easy to understand.

//

// This will be called whenever the >> operator is used

// with a CFraction object to the right of it.

// What happens is the system passes a reference to the

// stream to the left of the >>, and also

// a reference to the CFraction object. At this point 

// you are responsbile for accepting and parsing input for

// the stream passed to you.

//

// We return the istream& so that we can put multiple >>

// operations on a single line



 
istream& operator >> (istream& is, CFraction& fraction) {

 
 // Buffer to hold the input

 char input[64];
 
 // Get a line from the input stream passed

 is.getline(input, 64);

 // This variable will hold a pointer to the '/' or '\' seperator

 char *slash_pos = NULL;
 
 // Try to file a '/'

 slash_pos = strchr(input, '/');
 
 // If we could not find a '/' look for a '\'

 if (slash_pos == NULL)
 
  slash_pos = strchr(input, '\\');
 
 // If we didn't find either

 if (slash_pos == NULL) {
 
  // Was anything entered?

  if (strlen(input)) {
 
   // If so try to convert it to a number

   int numerator = atoi(input);
   
   // If we got a number then we'll make it numer_entered/1

   if (numerator) {
    
    fraction.SetNumerator(numerator);
    fraction.SetDenominator(1);

    return is;
 
   // Else we will set both the numerator and denominator to 0

   } else {
    
    fraction.SetNumerator(0);
    fraction.SetDenominator(0);

    return is;
 
   }

  // There was nothing entered, set both the

  // numerator and denominator to 0

  } else {
 
   fraction.SetNumerator(0);
   fraction.SetDenominator(0);

   return is;
 
  }
 
 }
 
 // Variable to hold the numerator string

 char str_numerator[32];
 
 // Copy the numerator out of the input string

 memcpy((void *)str_numerator, (void *)input, (slash_pos - input));
 
 // Variable to hold the integer version of the numerator

 int numerator = 0;
 
 // Convert the string to an integer

 numerator = atoi(str_numerator);
 
 // If we got a non-zero value then set the fraction's numerator 

 if (numerator) {

  fraction.SetNumerator(numerator);
 
 // If we got zero then the fraction is 0, so set both

 // the numerator and denominator to zero

 } else {
 
  fraction.SetNumerator(0);
  fraction.SetDenominator(0);

  return is;
 
 }

 // Variable to hold the denominator

 char str_denominator[32];
 
 // Copy the denominator out of the input string

 memcpy((void *)str_denominator, (void *)(slash_pos+1), 
    ((input + strlen(input)) - slash_pos));
 
 // Variable to hold the integer version of the denominator

 int denominator = 0;
 
 // Convert the string to an integer

 denominator = atoi(str_denominator);
 
 // Did we get a non-zero number for the denominator?

 // If so, set it

 if (denominator) {
  
  fraction.SetDenominator(denominator);
 
 // If not then the fraction is undefined, set both the

 // numerator and denominator to zero

 } 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) {

 
  // Test the three constructors and << operator


  // Supply both numerator and demoninator 

  CFraction *obj = new CFraction(2, 3);
  cout << "Testing (2/3): \t\t";
  cout << *obj << endl;
  delete obj;

 
  // Supply numerator only

  obj = new CFraction(4);
  cout << "Testing (4): \t\t";
  cout << *obj << endl;
  delete obj;

 
  // Default constructor with no arguments 

  obj = new CFraction();
  cout << "Testing (no args): \t";
  cout << *obj << endl << endl;
  delete obj;

 

  // Accept fractions and display them before and after normalization

  // until ctrl-c is pressed


  while(1) {
  
    obj = new CFraction();
    cout << "Enter a fraction (ctrl-c to exit): ";
 
    // This calls our overloaded >> operator because

    // a CFraction object is to the right of it

    cin >> *obj;
 
    // The << *obj calls our overloaded << operator because

    // a CFraction object is to the right of it

    cout << endl << "You entered (before normalization): " << *obj;
 
    obj->Normalize();

    // The << *obj calls our overloaded << operator because 

    // a CFraction object is to the right of it

    cout << endl << "You entered (after normalization): " 
        << *obj << endl << endl;
    delete obj;
 
    }
 
}

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here