JMU
Operator Overloading in C++
An Introduction


Prof. David Bernstein
James Madison University

Computer Science Department
bernstdh@jmu.edu


Motivation
Motivation (cont.)
Ignoring Some Details to Start
Operator "Functions"
Operator "Functions" (cont.)
Operator "Functions" (cont.)
An Example - The Specification
cppexamples/operatoroverloading/functions/Weight.h
        #ifndef edu_jmu_cs_Weight_h
#define edu_jmu_cs_Weight_h

/**
 * A Weight (in pounds and ounces).
 *
 * @author  Prof. David Bernstein, James Madison University
 */
class Weight {
 public:
  // These attributes are public so that they
  // are easily accessible in the operators
  int ounces, pounds;

  /**
   * Explicit Value Constructor
   *
   * @param lb   The pounds
   * @param oz   The ounces
   */
  Weight(int lb, int oz);

  /**
   * Default Constructor
   */
  Weight();

  /**
   * Convert a Weight into a printable string
   *
   * @return     A pointer to the string
   */
  char *toString(void);

  /**
   * The assignment operator
   *
   * @operand  b   The right-hand-side Weight
   */
  void operator =(const Weight &b);
};

/**
 * The addition operator
 *
 * @operand a  The first Weight
 * @operand b  The other Weight
 */
Weight operator+(const Weight &a, const Weight &b);

/**
 * The multiplication operator (i.e. multiplication
 * by a scalar)
 *
 * @operand a  The Weight
 * @operand k  The multiplier
 */
Weight operator *(const Weight &a, float k);

#endif
        
Operator "Functions" (cont.)
An Example - The Implementation
cppexamples/operatoroverloading/functions/Weight.cpp
        #include <math.h>
#include <stdio.h>
#include <iostream>
#include "Weight.h"

Weight::Weight(int lb, int oz) {
  pounds = lb;
  ounces = oz;

  if ((pounds < 0) || (ounces < 0)) {
    pounds = 0;
    ounces = 0;
  } else if (ounces >= 16) {
    pounds += ounces / 16;
    ounces = ounces % 16;
  }
}

Weight::Weight() {
  pounds = 0;
  ounces = 0;
}

Weight operator+(const Weight &a, const Weight &b) {
  int rOunces, rPounds;

  rPounds = a.pounds + b.pounds;
  rOunces = a.ounces + b.ounces;

  // Since this method returns by value this is OK
  // (i.e., a copy is made and returned)
  return Weight(rPounds, rOunces);
}

Weight operator *(const Weight &a, float k) {
  int totalOunces;

  if (k < 0.0)
    k = 1.0;

  totalOunces = static_cast<int>((static_cast<float>(a.pounds) * k) * 16.0
      + (static_cast<float>(a.ounces) * k));

  // Return by value
  return Weight(0, totalOunces);
}

void Weight::operator =(const Weight &b) {
  pounds = b.pounds;
  ounces = b.ounces;
}

/**
 * Convert a Weight into a printable string
 *
 * @return     A pointer to the string
 */
char *Weight::toString(void) {
  char *str;
  int n;

  n = 1;

  if (pounds > 0)
    n += static_cast<int>(log10(pounds) + 1 + 4);
  else
    n += 1 + 4;

  if (ounces > 0)
    n += static_cast<int>(log10(ounces) + 1 + 2);
  else
    n += 1 + 2;

  str = new char[n];
  snprintf(str, n, "%dlbs %doz", pounds, ounces);

  return str;
}

        
Operator "Functions" (cont.)
An Example - Use
cppexamples/operatoroverloading/functions/Driver.cpp
        #include <iostream>
using namespace std;

#include "Weight.h"

/**
 * \file
 * An example that uses the Weight class v1.0
 * (illustrating operator overloading)
 *
 * @author  Prof. David Bernstein, James Madison University
 */

/**
 * The entry point of the application
 *
 * @return  1
 */
int main(void) {
  Weight flourForCookies(10, 12), flourForCake(3, 4);
  Weight flourTotal;
  Weight flourForDoubleCookies;
  Weight flourForHalfCake;

  flourTotal = flourForCookies + flourForCake;
  flourForDoubleCookies = flourForCookies * 2.0;
  flourForHalfCake = flourForCake * 0.5;

  cout << "\n\n\n";

  cout << "Flour for cookies and cake: " << flourTotal.toString() << "\n";

  cout << "Flour for double batch of cookies: "
       << flourForDoubleCookies.toString() << "\n";

  cout << "Flour for half-size cake: " << flourForHalfCake.toString() << "\n";

  return 1;
}
        
Operator "Methods"
Operator "Methods" (cont.)
An Example - The Specification
cppexamples/operatoroverloading/methods/Weight.h
        #ifndef edu_jmu_cs_Weight_h
#define edu_jmu_cs_Weight_h

/**
 * A Weight (in pounds and ounces).
 *
 * @author  Prof. David Bernstein, James Madison University
 */
class Weight {
 private:
  int ounces, pounds;

 public:
  /**
   * Explicit Value Constructor.
   *
   * @param lb   The pounds
   * @param oz   The ounces
   */
  Weight(int lb, int oz);

  /**
   * Default Constructor.
   */
  Weight();

  /**
   * Convert a Weight into a printable string.
   *
   * @return     A pointer to the string
   */
  char *toString(void);

  /**
   * The assignment operator.
   *
   * @param  b   The right-hand-side Weight
   */
  void operator =(const Weight &b);

  /**
   * The addition operator.
   *
   * Note: this is the first Weight
   *
   * @param b     The other Weight
   */
  Weight operator+(const Weight &b) const;

  /**
   * The multiplication operator (i.e. multiplication
   * by a scalar).
   *
   * Note:  this is the Weight
   *
   * @param k     The multiplier
   */
  Weight operator *(float k) const;
};

#endif
        
Operator "Methods" (cont.)
An Example - The Implementation
cppexamples/operatoroverloading/methods/Weight.cpp
        #include <math.h>
#include <stdio.h>
#include <iostream>
#include "Weight.h"

Weight::Weight(int lb, int oz) {
  pounds = lb;
  ounces = oz;

  if ((pounds < 0) || (ounces < 0)) {
    pounds = 0;
    ounces = 0;
  } else if (ounces >= 16) {
    pounds += ounces / 16;
    ounces = ounces % 16;
  }
}

Weight::Weight() {
  pounds = 0;
  ounces = 0;
}

Weight Weight::operator+(const Weight &b) const {
  int rOunces, rPounds;

  rPounds = pounds + b.pounds;
  rOunces = ounces + b.ounces;

  // Since this is a return by value it's OK
  // (i.e., a copy is made)
  return Weight(rPounds, rOunces);
}

Weight Weight::operator *(float k) const {
  int totalOunces;

  if (k < 0.0)
    k = 1.0;

  totalOunces = static_cast<int>((static_cast<float>(pounds) * k) * 16.0
      + (static_cast<float>(ounces) * k));

  // Return by value
  return Weight(0, totalOunces);
}

void Weight::operator =(const Weight &b) {
  pounds = b.pounds;
  ounces = b.ounces;
}

char *Weight::toString(void) {
  char *str;
  int n;

  n = 1;

  if (pounds > 0)
    n += static_cast<int>(log10(pounds) + 1 + 4);
  else
    n += 1 + 4;

  if (ounces > 0)
    n += static_cast<int>(log10(ounces) + 1 + 2);
  else
    n += 1 + 2;

  str = new char[n];
  snprintf(str, n, "%dlbs %doz", pounds, ounces);

  return str;
}

        
Operator "Methods" (cont.)
An Example - Use
cppexamples/operatoroverloading/methods/Driver.cpp
        #include <iostream>
#include <string>
#include "Weight.h"

using namespace std;

/**
 * \file
 * An example that uses the Weight class v1.0
 * (illustrating operator overloading)
 *
 * @author  Prof. David Bernstein, James Madison University
 */

/**
 * The entry point of the application
 *
 * @return  1
 */
int main(void) {
  Weight flourForCookies(10, 12), flourForCake(3, 4);
  Weight flourTotal;
  Weight flourForDoubleCookies;
  Weight flourForHalfCake;

  flourTotal = flourForCookies + flourForCake;
  flourForDoubleCookies = flourForCookies * 2.0;
  flourForHalfCake = flourForCake * 0.5;

  cout << "\n\n\n";

  cout << "Flour for cookies and cake: " << flourTotal.toString() << "\n";

  cout << "Flour for double batch of cookies: "
       << flourForDoubleCookies.toString() << "\n";

  cout << "Flour for half-size cake: " << flourForHalfCake.toString() << "\n";

  return 1;

}
        
Return by Value/Reference
The Assignment Operator
The Assignment Operator (cont.)
The Assignment Operator (cont.)