Arithmetic Operators

Sometimes we invent a class to provide an additional type of numeric variable. For instance:

To make a class of this sort useful, we need to be able to use it in ordinary arithmetic expressions like A + B, C / D, H++, or G -=2. This will require us to redefine the arithmetic operators.


The Rational class

For illustration, we will use the Rational class:

     class Rational
     {
      private:
       int Num;                        //Numerator of a fraction
       int Den;                        //Denominator of a fraction 
      public:
       Rational();                     //basic constructor
       Rational(const Rational &);     //copy constructor
       Rational(const int &, const int &);
                                       //initializing constructor
       ...lots of other methods...
     };

There are many methods we might want to have in this class, but for now, we will look just at the arithmetic operators.


Addition operator

Suppose we have a couple of instances of Rational:

     Rational A;
     Rational B;

and we want to make sense out of the expression A + B. We need to redefine operator + for the Rational class. There are some decisions to make:

We can now write the prototype statement:

     Rational operator +(const Rational &) const;

and the code should look something like this:

     Rational::Rational operator +(const Rational & Other) const
     {
      int T, B;
      T = Num * Other.Den + Den * Other.Num;
      B = Den * Other.Den;
      Rational NewRat(T, B);
      return NewRat;
     }

Notice here that NewRat is a local variable and will disappear after the return statement, as C++ cleans up after the function call. What we are returning is a copy of NewRat.

It should be possible to use expressions such as A + B + C + D. This will be evaluated from left to right as ((A + B) + C) + D.

After this, it should be clear how we can redefine the operators for subtraction, multiplication and division. (The remainder operator does not seem to make sense for the Rational class.)

If we wanted to make operator + a friend of the class instead, we would need a different prototype statement:

     friend Rational operator +(const Rational &, const Rational &);

and the code would be a bit different as well:

     Rational::Rational operator +(const Rational & First, const Rational & Second)
     {
      int T, B;
      T = First.Num * Second.Den + First.Den * Second.Num;
      B = First.Den * Second.Den;
      Rational NewRat(T, B);
      return NewRat;
     }


The += operator

Although we could easily get along without it, C++ allows us to write

     A += B;

instead of

     A = A + B;

if we like. How can we redefine operator += for the Rational class?

Again, we can make this a method of the class, and again, the argument (B) will not be changed, so it can be a constant reference. In this case, though, we want to change the value of the current instance, so we will not have a constant method.

What should the operator return? We can have expressions such as

     A = B += C;

This will be evaluated from right to left, as

     A = (B += C);

Thus the += operator does have to return something, and in fact it should return the new value of the current instance. To avoid an extra copy operation, we can have it return a reference to a Rational.

The prototype statement should be:

     Rational & operator +=(const Rational &);

and the code should be something like this:

     Rational & Rational::operator +=(const Rational & Other)
     {
      int T, B;
      T = Num * Other.Den + Den * Other.Num;
      B = Den * Other.Den;
      Num = T;
      Den = B;
      return &this; 
     }

Notice we are returning *this. Here this is a pointer to the current instance (provided automatically in every class).

We could easily make operator += a friend function instead of a method.

After this, it should be clear how we can redefine the operators -=, *= and /=. (The remainder operator does not seem to make sense for the Rational class.)


The increment operators

Although we could easily get along without it, C++ allows us to write

     A++;

instead of

     A = A + 1;

if we like. How can we redefine operator += for the Rational class? We will assume that we are actually adding 1/1 rather than the integer 1.

To make life more complicated, C++ also allows us to use

     ++A;

What is the difference between these?

The version in which the two + signs follow the variable (A++) is called the post-increment operator and has this characteristic: If we write

     A = 3;
     B = A++;

then afterward, B has the value 3 and A has the value 4. That is, "do something with the value of A, and then increment A".

The version in which the two + signs precede the variable (++A) is called the pre-increment operator and has this characteristic: If we write

     A = 3;
     B = ++A;

the afterward, A has the value 4 and so does B. That is, "increment A and then do something with the value of A".

Here the "do something with" part refers to an assignment statement, but in general, it could be anything. The difference clearly is in what we return from the operators.

Neither operator has any arguments, and they have the same name, "operator ++", so how can the compiler tell them apart? In code that uses the operators, it can tell by the notation: the symbol comes before or after the variable. Still, the code has to be compiled, and to avoid having two functions with the same name and the same argument list, we resolve this by giving the post-increment operator a dummy argument.

The two prototype statements are:

     Rational & operator ++();      //pre-increment

and

     Rational operator ++(int = 0); //post-increment

Notice that for the post-increment operator, we have an argument with a default value of 0. It is never coded when the operator is used, but it does no harm, and the compiler is able to tell the two apart.

The code for the operators looks something like this:

     Rational & Rational::operator ++()       //pre-increment
     {
      Num += Den;
      return *this;
     }

     Rational Rational::operator(int Dummy)   // post-increment
     {
      Rational NewRat(&this);
      Num += Den;
      return NewRat;        
     }

The reader may want to check that these actually do what they are supposed to do.

There are similar operators called pre-decrement (--A) and post-decrement (A--). It should be clear how we can redefine these operators for the Rational class.

Any or all of these four operators could easily be a friend function instead of a method.


Other arithmetic operators

There are various other operators we might want to work with for one class or another. Not all of them make sense for the Rational class.

The reader might find it interesting to work out how to redefine the unary minus operator (-A). It has no arguments and does not change the value of the current instance. (There is also a unary plus operator (+A), but it's not clear why.)

Other operators of this sort include the bitwise logical operators | (OR), & (AND) and ^ (XOR) and the corresponding |=, &= and ^= operators. There are also shift operators << (left shift) and >> (right shift), which correspond to multiplying and dividing, respectively, by powers of 2.