11.8.2. fraction 2 Example (Overloaded Operators Version)

Review

Version 2 of the fraction example replaces the arithmetic and I/O functions with overloaded operators. It also refers to examples presented earlier in this chapter. Please review the following as needed:

Previous sections presented most of the fraction class's features as examples of overloaded operators implemented as either member or friend functions. All that remains is presenting the example in its entirety. The friend or non-member version of the arithmetic operators is the most economical implementation and, therefore, the version presented here.

#pragma once

#include <iostream>
using namespace std;

class fraction
{
    private:
        int     numerator;
        int     denominator;

    public:
                  fraction(int n = 0, int d = 1);

        friend    fraction operator+(fraction f1, fraction f2);
        friend    fraction operator-(fraction f1, fraction f2);
        friend    fraction operator*(fraction f1, fraction f2);
        friend    fraction operator/(fraction f1, fraction f2);

        friend    ostream& operator<<(ostream& out, fraction& f);
        friend    istream& operator>>(istream& in, fraction& f);
};
  • A fraction has two member variables: numerator and denominator
  • Default arguments ⇒ 3 constructor roles
  • Four fraction operators
  • fraction inserter and extractor operators
fraction.h. The complete fraction class specification includes the default arguments and the friend keyword (neither of which appear in the function definitions below).
#include <iostream>
#include "fraction.h"
using namespace std;

int gcd(int u, int v);

fraction::fraction(int n, int d) : numerator(n), denominator(d)
{
    int    common = gcd(numerator, denominator);
    numerator /= common;
    denominator /= common;
}

fraction operator+(fraction f1, fraction f2)
{
    int    n = f1.numerator * f2.denominator +
                f2.numerator * f1.denominator;
    int    d = f1.denominator * f2.denominator;

    return fraction(n, d);
}

fraction operator-(fraction f1, fraction f2)
{
    int    n = f1.numerator * f2.denominator -
                f2.numerator * f1.denominator;
    int    d = f1.denominator * f2.denominator;

    return fraction(n, d);
}

fraction operator*(fraction f1, fraction f2)
{
    int    n = f1.numerator * f2.numerator;
    int    d = f1.denominator * f2.denominator;

    return fraction(n, d);
}

fraction operator/(fraction f1, fraction f2)
{
    int    n = f1.numerator * f2.denominator;
    int    d = f1.denominator * f2.numerator;

    return fraction(n, d);
}

ostream& operator<<(ostream& out, fraction& f)
{
    cout << endl << f.numerator << "/" << f.denominator << endl;

    return out;
}

istream& operator>>(istream& in, fraction& f)
{
    cout << "Please enter the numerator: ";
    cin >> f.numerator;
    cout << "Please enter the denominator: ";
    cin >> f.denominator;

    return in;
}

// Euclid's Algorithm for finding the greatest common divisor

int gcd(int u, int v)
{
    u = (u < 0) ? -u : u;
    v = (v < 0) ? -v : v;

    while (u > 0)
    {
        if (u < v)
        {
            int t = u;    // swap u and v
            u = v;
            v = t;
        }

        u -= v;
    }

    return v;            // the GCD of u and v
}
  • One constructor, three possible calls:
    • fraction f;
    • fraction f(5);
    • fraction f(2, 3);
    • Reduces new fraction to lowest terms
  • We must pass all arguments to friend functions explicitly inside the parentheses, and we must explicitly name the objects when accessing their member variables
  • The advantage of constructing the new fraction at the end of the function, after the calculations are done, is that it allows the constructor to reduce the fraction to lowest terms
  • Programmers specify the output format of the printed object. out may refer to any output stream - the console, a file, etc.
  • in may refer to any input stream, including a file. It's possible that the operator may be used in a program that processes a file unattended (i.e., without an operator present). So, it may not be advisable to include prompts in an extractor operator
fraction.cpp. The complete implementation of the fraction class functions, including overloaded operators, and the greatest common divisor function. The arithmetic (+, -, *) and I/O (<<, >>) operators are non-members (i.e., friend) functions, but the "friend" keyword only appears in the class specification. The example demonstrates the syntax programmers use to access member variables with friend functions.
#include "fraction.h"
#include <iostream>
using namespace std;

void input(fraction& f, char* prompt);

int main()
{
    char    choice;

    do
    {
        cout << "A\tAdd\n";
        cout << "S\tSub\n";
        cout << "M\tMult\n";
        cout << "D\tDiv\n";
        cout << "E\tExit\n";

        cout << "\nChoice?: ";

        cin >> choice;
        cin.ignore();

        if (choice == 'E' || choice == 'e')
            break;

        fraction    left;
        fraction    right;
        fraction    result;

        switch (choice)
        {
            case 'A':
            case 'a':
                input(left, "Enter the left operand: ");
                input(right, "Enter the right operand: ");
                result = left + right;
                break;
            case 'S':
            case 's':
                input(left, "Enter the left operand: ");
                input(right, "Enter the right operand: ");
                result = left - right;
                break;
            case 'M':
            case 'm':
                input(left, "Enter the left operand: ");
                input(right, "Enter the right operand: ");
                result = left * right;
                break;
            case 'D':
            case 'd':
                input(left, "Enter the left operand: ");
                input(right, "Enter the right operand: ");
                result = left / right;
                break;
            default:
                cerr << "Unrecognized choice: " << choice << endl;
                break;
        }

        cout << result << endl;

    } while (choice != 'e' && choice != 'E');

    return 0;
}

void input(fraction& f, char* prompt)
{
    cout << prompt;
    cin >> f;
}
  • input function uses operator >>
  • Prints a simple menu
  • Enter a single character and press Enter
  • Discards the new-line character
  • End the loop when the user selects "Exit"
  • fraction objects for the left and right operands, and the result of the operation
  • Calling operator +
  • Calling operator -
  • Calling operator *
  • Calling operator /
  • Calling operator <<
  • Calling operator >>
calc.cpp. The calc program implements a simple fraction calculator, and is the "client" that uses the fraction class. It demonstrates how to define fraction objects (but only illustrates one of the three constructor options) and how to use the fraction operators.

Downloadable Code

ViewDownload
fraction.h fraction.h
fraction.cpp fraction.cpp
calc.cpp calc.cpp