Operator Overloading

Operator overloading is the ability to enable the C++ operators to work with class objects.

The C++ language already overloads the plus (+) and minus (-) signs for us. These operators perform differently depending on their context in integer arithmetic, floating-point arithmetic, and pointer arithmetic.

To overload an operator, a function must be written with the name operator followed by the symbol for the operator being overloaded.

To use an operator on class objects, that operator MUST be overloaded - with two exceptions.

  1. assignment operator (=)
  2. ampersand (&)

The function to overload an operator can be defined as either a member or non-member function of a class.

Member Functions

Binary Operators

The compiler will treat an expression of the form:

a @ b

where a is a class object, @ is the operator, and b is the only explicit argument passed to the function. Therefore, it will be treated like:

a.operator@(b)

Member functions take advantage of the this pointer, which is a pointer maintained by each object that refers to itself. this is an implicit argument in all references to members within that object and can also be used to obtain the address of the object.

The generic format for overloading a binary operator (as a class member):

prototype:   return_type  operator@(argument_data_type);


function:    return_type  class_name::operator@(arg_data_type  arg_name)
                {
                code goes here
                }

Some of the binary operators can be "strung" together when they are used. In order for this to work correctly, the function must return a reference to an object, this is accomplished by returning *this.

Unary Operators

The compiler will treat an expression of the form:

@a

where a is a class object and @ is the operator as a function call like:

a.operator@()

The generic format for overloading a unary operator (as a class member):

prototype:   return_type  operator@();


function:    return_type  class_name::operator@()
                {
                code goes here
                }

Non-member Functions

Non-member functions usually need to have access to members of a class, but since the function is not a class member, it won't have access to the private data.

To get around this problem, C++ implemented the idea of friends of a class.

A friend function of a class is defined outside that class's scope, yet has the right to access private members of the class.

To declare a function as a friend of a class, precede the function prototype in the class definition with the keyword friend.

A few rules about friendship:

  1. The prototype for a friend function usually precedes all public and private member definitions.

  2. A class may also be declared to be a friend of another class.

  3. Friendship is granted, not taken -- for class B to be a friend of class A, class A must declare that class B is its friend

  4. Friendship is not symmetric -- just because class A is a friend of class B, does not mean that class B is a friend of class A

  5. Friendship is not transitive -- if class A is a friend of class B, and class B is a friend of class C, then it is not true to say that class A is a friend of class C

Binary Operators

The compiler will treat an expression of the form:

a @ b

where either a or b is a class object and @ is the operator as the following function call:

operator@(a, b)

Two of the commonly overloaded operators which are implemented as non-member functions are the stream insertion (<<) and extraction (>>) operators.

In the class definition:   friend ostream & operator<<(ostream &, const X &);

Outside the class:         ostream & operator<<(ostream &output, const X &obj)
                             {
                             output << obj.i;

                             return output;
                             }

Unary Operators

The compiler will treat an expression of the form:

@a

where a is either a class object or reference to an object, and @ is the operator as a function call like:

operator@(a)

The generic format for overloading a unary operator (as a non-member):

prototype:   return_type operator@(class_name);      OR

                         return_type operator@(class_name &);


function:    return_type operator@(class_name object_name)
                {
                code goes here
                }