Click here to Skip to main content
16,017,285 members
Articles / Programming Languages / C++
Article

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

Rate me:
Please Sign up or sign in to vote.
4.47/5 (12 votes)
9 May 2003CPOL1 min read 209.6K   1.4K   23   12
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, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer (Senior)
United States United States
I started learning C and 68K assembly language on an Atari ST around 1985 or so using the Mark Williams compiler. I was instantly hooked.

My favorite languages are: C/C++, C#, Ruby, and Python.

My first PC clone was a 386SX-25MHz with 4MB of RAM. OMG | :OMG:

Comments and Discussions

 
Generalthis is a great post Pin
Southmountain28-Jan-20 8:03
Southmountain28-Jan-20 8:03 
QuestionConfusion... Pin
Atul Khanduri27-Feb-14 20:08
Atul Khanduri27-Feb-14 20:08 
Generalfind largest number without using loop constructs and if else, Pin
amanraj000114-Feb-11 17:27
amanraj000114-Feb-11 17:27 
Generaloperator overloading Pin
Member 15751428-Dec-04 3:52
Member 15751428-Dec-04 3:52 
GeneralEuclid's theorem Pin
willyboy123419-May-03 13:05
willyboy123419-May-03 13:05 
GeneralRe: Euclid's theorem Pin
Dana Holt19-May-03 17:11
Dana Holt19-May-03 17:11 
GeneralOne little math-bug Pin
Patrick Luja13-May-03 20:58
Patrick Luja13-May-03 20:58 
GeneralRe: One little math-bug Pin
Dana Holt14-May-03 7:48
Dana Holt14-May-03 7:48 
GeneralNice. Useful for C++ introduction. Pin
Patje12-May-03 2:04
Patje12-May-03 2:04 
GeneralRe: Nice. Useful for C++ introduction. Pin
Dana Holt14-May-03 7:52
Dana Holt14-May-03 7:52 
Thank you.

Yes, I know what you mean about many new programmers not knowing how to write a class from scratch. This is something that every programmer needs to know because when the wizards make a mistake or things need to be tweaked that's the only way to do it.

I do plan on extending this class to include overloading of the +, -, /, and * operators when I have the time.



--
Dana Holt
Xenos Software LLC
GeneralRe: Nice. Useful for C++ introduction. Pin
michael2003au19-Nov-03 15:04
michael2003au19-Nov-03 15:04 
GeneralRe: Nice. Useful for C++ introduction. Pin
Robert M Greene9-Sep-05 9:13
Robert M Greene9-Sep-05 9:13 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.