越而胜己 / Beyond awesome

I'm learning C++ recently, and I asked my friend Debbie for his C++ homework on implementing LongLongInt with strings in C++. The implementation is quite simple, but the operator overloading confused me. Operator overloading is not available in Java, but is definitely an important technique in C++ class implementation. Therefore, I looked at C++ Primer and Primer Plus to figure out how they work.

Let's say we have a class Time.

class Time {
private:
  int minutes;
  int hours;
public:
  int getMinutes();
  int getHours();
}

We have variables t1 and t2, and we want to add them to get t3. In Java, we would give the Time class an Time add(Time other) method and get t3 by calling Time t3 = t1.add(t2).

In C++, it's pretty much the same. There is a similar function implemented in C++ called operator+. If we overload the function and declare Time operator+(const Time &other), we can use the function like this: Time t3 = t1.operator+(t2) to perform the addition. What's special about this function is that it can be written as Time t3 = t1 + t2:

Time operator+(const Time &other) {
  Time result;
  result.minutes = minutes + other.minutes;
  result.hours = hours + other.hours + result.minutes / 60;
  result.minutes %= 60;
  return result;
}

Similarly, real number multiplication can be implemented as below:

Time operator*(double m) {
  Time result;
  result.minutes = (int) ((hours * 60 + minutes) * m);
  result.hours = result.minutes / 60;
  result.minutes %= 60;
  return result;
}

The multiplication operator will be translated as t2 = t1.operator*(1.5).

However, if we want to do t2 = 1.5 * t1, the compiler will give us an error, because this operation will be translated as 1.5.operator*(t1), but we haven't (and can't) overloaded operator* for double.

Luckily there is another solution. We can overload a nonmember function Time operator*(double m, const Time &t).

Time operator*(double m, const Time &t) {
  return t * m; // because operator* is already implemented correctly
}

But there is still one more problem. We are trying to access minutes and hours from outside the class, but these fields are private and we can't access them directly. Fortunately, we can make Time operator*(double m, const Time &t) as a friend of our class by declaring friend Time operator*(double m, const Time &t); in the class.

class Time {
private:
  int minutes;
  int hours;
public:
  int getMinutes();
  int getHours();
  Time operator+(const Time &other) {
    Time result;
    result.minutes = minutes + other.minutes;
    result.hours = hours + other.hours + result.minutes / 60;
    result.minutes %= 60;
    return result;
  }
  Time operator*(double m) {
    Time result;
    result.minutes = (int) ((hours * 60 + minutes) * m);
    result.hours = result.minutes / 60;
    result.minutes %= 60;
    return result;
  }
  friend Time operator*(double m, const Time &t);
}

Time operator*(double m, const Time &t) {
  return t * m; // because operator* is already implemented correctly
}

Thus, we have implemented the multiplication operator for our Time class.