Section 4.2
Overloading operators
cplusplus.com

C++ incorporates the option to use language standard operators between classes in addition to between fundamental types. For example:

int a, b, c;
a = b + c;
is perfectly valid, since the different variables of the addition are all fundamental types. Nevertheless, is not so obvious that we can perform the following operation (in fact it is incorrect):
struct { char product [50]; float price; } a, b, c;
a = b + c;
The assignation of a class (or struct) to other one of the same type is allowed (default copy constructor). What would produce an error would be the addition operation, that in principle is not valid between non-fundamental types.

But thanks to the C++ ability to overload operators, we can get to do that objects derived from composed types as the previous one can accept operators which would not accept otherwise or even modify the effect of operators which they already admit. Here is a list of all the operators that can be overloaded:

+    -    *    /    =    <    >    +=   -=   *=   /=   <<   >>
<<=  >>=  ==   !=   <=   >=   ++   --   %    &    ^    !    |
~    &=   ^=   |=   &&   ||   %=   []   ()   new  delete
To overload an operator we only need to write a class member function whose name is operator plus the operator sign that we want to overload, following this prototype:
type operator sign (parameters);
Here you have an example that includes the operator +. We are going to sum the bidimensional vectors a(3,1) and b(1,2). The addition of two bidimensional vectors is an operation as simple as to add the two x coordinates to obtain the resulting x coordinate and to add the two y coordinates to obtain the resulting y. In this case the result will be (3+1,1+2) = (4,3).

// vectors: overloading operators example
#include <iostream.h>

class CVector {
  public:
    int x,y;
    CVector () {};
    CVector (int,int);
    CVector operator + (CVector);
};

CVector::CVector (int a, int b) {
  x = a;
  y = b;
}

CVector CVector::operator+ (CVector param) {
  CVector temp;
  temp.x = x + param.x;
  temp.y = y + param.y;
  return (temp);
}

main () {
  CVector a (3,1);
  CVector b (1,2);
  CVector c;
  c = a + b;
  cout << c.x << "," << c.y;
  return 0;
}
4,3

If you are baffled seeing so many CVector consider that some of them make reference to the class name CVector and others are functions with that name (constructor and destructor). Do not confuse them:

CVector (int, int);            // function name CVector (constructor)
CVector operator+ (CVector);   // function operator+ that returns CVector type
The function operator+ of class CVector is the one that is in charge of overloading the arithmetic operator +. This one can be called by any of these two ways:
c = a + b;
c = a.operator+ (b);

Notice also that we have incuded the empty constructor (without parameters) and we have defined it with a no-op block of instructions:
CVector () { };
this is necessary, since there already exists another constructor,
CVector (int, int);
and if so none of the default constructors will exist in CVector if we do not explicitly declare it like we have done. Otherwise the declaration
CVector c;
included in main() would not be valid.

Anyway, I have to warn you that a no-op block is not suggested for a constructor, since it does not fulfill the minimum functionality that a constructor should have, which is the initialization of all the variables in the class. In our case this constructor leaves variables x and y without being defined. Therefore, a more advisable declaration would have been something similar to this:

CVector () { x=0; y=0; };
that for simplicity I have not included in the code.

As well as a class includes certain default constructors, it also includes a default definition for the assignation operator (=) between two classes of the same type. This copies the whole content of the non-static members of the parameter object (the one at the right side of the sign) to the left side one. Of course you can redefine it by any other functionality that you want for this operator, like for example, copy only certain class members.

The overload of operators does not force that its operation bears a relation to the mathematical meaning of the operator, although it is recommended. For example, it is not much logic to use the operator + to subtract two classes or the operator == to fill with zeros a class, although is perfectly possible to do so.

Although the prototype of a function operator+ can seem obvious since it takes the right side of the operator as the parameter for the function operator+ of the left side object, other operators are not so clear. Here you have a table with a summary on how the different operator functions must be declared (replace @ by the operator in each case):

Expression Operator (@) Function member Global function
@a + - * & ! ~ ++ -- A::operator@() operator@(A)
a@ ++ -- A::operator@(int) operator@(A, int)
a@b + - * / % ^ & | < > == != <= >= << >> && || , A::operator@(B) operator@(A, B)
a@b = += -= *= /= %= ^= &= |= <<= >>= [ ] A::operator@(B) -
a(b, c...) () A::operator()(B, C...) -
a->b -> A::operator->() -
* where a is an object of class A, b is an object of class B and c is an object of class C.
You can see that in this panel they appear two ways to overload some class operators: as member function and as global function. Its use is indistinct, nevertheless I remind you that functions that are not members of a class cannot access the private or protected member of the same one unless the global function is friend to the class (friend is explained ahead).

The keyword this

The keyword this represents within a class the address of the object of this same class that is calling the member in which this keyword is included.

It can be used to check if a parameter passed to a member function of an object is the object itself. For example,

// this
#include <iostream.h>

class CDummy {
  public:
    int isitme (CDummy& param);
};

int CDummy::isitme (CDummy& param)
{
  if (&param == this) return 1;
  else return 0;
}

main () {
  CDummy a;
  CDummy* b = &a;
  if ( b->isitme(a) )
    cout << "yes, &a is b";
  return 0;
}
yes, &a is b

It is also frequenty used in operator= member functions that return objects by reference (avoiding the use of temporary objects). Following with the vector's examples seen before we could have written an operator= function like this:

CVector& CVector::operator= (const CVector& param)
{
  x=param.x;
  y=param.y;
  return *this;
}
In fact this is the default code generated for the class if we include no operator= member function.

Static members

A class can contain static members, either data and functions.

Static data members of a class are also known as "class variables", because their content does not depend on any object. There only exists a unique value for all the objects of that same class.

For example, it may be used for that a variable within a class can contain the number of declared objects of that class, like in the following example:

// static members in classes
#include <iostream.h>

class CDummy {
  public:
    static int n;
    CDummy () { n++; };
    ~CDummy () { n--; };
};

int CDummy::n=0;

main () {
  CDummy a;
  CDummy b[5];
  CDummy * c = new CDummy;
  cout << a.n << endl;
  delete c;
  cout << CDummy::n << endl;
  return 0;
}
7
6

In fact, static members are global variables but with class scope. For that reason, and to avoid that they may be declared several times, according to ANSI-C++ standard, we can only include the protype (declaration) in the class declaration and not the definition (initialization). Then we must include a formal definition in the global scope (like in the previous example), where we will be able to assign an initial value to it.

Because it is a unique variable for all the objects of the same class, this can be referred as a member of any object of that class or even directly by the class name (of course this is only valid for static members):

cout << a.n;
cout << CDummy::n;
These two outputs of the previous example are referring to the same variable: the static variable n of the class CDummy.

Once again, I remind you that in fact it is a global variable. The only difference is its name outside the class.

Like we may include static data within a class we can also include static functions. They represent the same: they are global functions that are called as if they were object members of a given class. They can only refer to static data, in no case to nonstatic members of the class, as well as they do not allow the use of keyword this, since it makes reference to an object pointer and these functions in fact are not members of any object but directly members of the class.

© The C++ Resources Network, 2000 - All rights reserved

Previous:
4-1. Classes.

index
Next:
4-3. Relations between classes. Inheritance.