top of page

Operator Overloading - II.

 

Let us consider some special cases of operator overloading.

Overloading of subscript operator:

 

Subscript operator (square brackets []) can be overloaded to access the dynamically allocated array elements within an object. Using subscript operator, we can treat these objects like a POD arrays and access ith element of the array using []

Output

    0 1 4 9 16 25 36 49 64 81

We have overloaded subscript operator using two overloaded functions. The first one which returns a reference to an integer can be used to modify the array. Second one can be used to read the elements without modifying them and can also be used for constant objects.

The parameter to operator function n is the index of the array.

We are writing values to array elements inside obj1 using [] operator (obj[i]  ) and then we are displaying these elements.

Exercise:

Write a string class which stores the characters in a dynamic character array and then lets you modify or display individual characters using subscript operator.

Increment and Decrement operators

 

Increment (++) and decrement (--) operators have prefix and postfix versions for PODs. e.g.a++ and ++a. 

 

So do we overload these operators with two versions ? If yes, how?

 

The solution is -  for postfix versions,  we should use a dummy integer parameter which is never used.

As mentioned earlier, we have overloaded both the versions of ++ operator. Prefix increment takes 0 parameters and postfix operator takes one int parameter. We have also ensured that the expected behavior of these operators (i.e. prefix incrementing the object and then returning it, postfix returning the previous value and incrementing the object)

In line 26, obj2 is assigned to prefix increment of obj. So obj2 will become 10. In line 27, obj2 is incremented using postfix and is assigned to obj. So obj becomes 10 and obj2 will be 11.

Overloading new operator:

 

new operator takes one parameter of type size_t (unsigned int) and returns a void (generic) pointer. The easy way of overloading new operator would be

Note that compiler provided new operator will be sufficient in most situations. You should overload new and delete operator, only if you want to use your own block of memory for dynamic allocation.

 

Insertion and Extraction operators (<< and >>)


These two operators are used to read and write objects from input-output streams and files. By overloading these two operators,  we can read the object directly from console using extraction operator and write objects on screen using insertion operator. We can also write objects to files and read objects from files.

 

These operators should always be overloaded as non-member functions  because their first parameter will not be the object of the given class but an iostream object.  >> must have istream object as first parameter and << must have ostream object as first parameter.

 

These two functions must return a reference to iostream objects in order to use chaining in i/o operation.

 

e.g.

     cin>>obj1>>obj2;

 

And it is necessary to use second parameter also as reference parameter in extraction operator (>>) because the operator function must modify the object.

To overload extraction operator for files, we must use ifstream in place of istream. Similarly to overload insertion operator for files, we have to use ofstream in place of ostream.

You should ensure that these two member functions are friends if you want them to access data directly.

Once >> is overloaded you can read the object directly using cin and once << is overloaded you can display the object directly using cout.


Number obj1(10);
cout<<obj1;/*displays 10*/
cin>>obj1;/*reads num of obj1*/

Conversion Operators:


Conversion operator functions are used to convert objects to other types.

 

Conversion operator functions are written without a return type. Instead, return type is the name of the operator.

 

For example, to convert object to integer, we must write an operator function with name  operator int and no return type.

Here we have written two conversion functions, operator int() and  operator float().

The line int m=obj calls int conversion operator, converts the object to integer and returns that. Similarly the line n=obj calls float conversion operator.

The output of the program will be

int conversion operator
m is 100
float conversion operator
n is 100

 

Function call operator:
 

parentheses - () can be overloaded to create an object which behaves like a function. Such objects are called function objects or functors.

Output
   1000

We are calling function call operator on cobj with parameter 10. The operator function cubes the parameter and returns it.

 
Overloading of assignment operator:

 

Compiler provides overloaded assignment operator function for every class. Along with copy constructor, destructor and default constructor.  But this assignment does  a shallow copy.

 

If your class does not use dynamic memory, then compiler provided assignment operator would be sufficient for your class. But if there is dynamically allocated memory in your class,  then you need deep copy and  you have to write your own assignment operator.

 

Assignment operator function looks almost like a copy constructor. You allocate memory and you copy elements. But before that, you should release memory allocated earlie.

 

There is one more problem however. What if you use a statement which involves references and parameters and which ultimately becomes self assignment (obj1 = obj1) ?

In this case, when you delete memory of lhs operand, pointer of rhs operand (which is same as lhs) becomes dangling pointer and all hell breaks loose.

 

To avoid this problem, you must check for self assignment before deleting memory and allocate new memory.

We first check if this pointer is equal to address of RHS operand to ensure that there is no self assignment. If this pointer is not equal to &obj1, then we release the previous memory, allocate memory with new operator and then copy all the elements.

Move assignment operator

 

Move assignment operator was introduced in C++11, to efficiently copy objects. In the case of such operators, the ownership of the data is transferred to destination object. The source object is in a valid but unspecified state.  It uses a parameter of the type rvalue reference (a reference which refers to a rvalue expression. It is defined using &&).

 

Syntax

class_name & class_name :: operator= ( class_name && )

In a copy assignment operator, if the object uses lot of resources, the process will be expensive. As during the operation, two copies the object are present in memory for some duration. To avoid this, we can move assignment operator.

bottom of page