Skip to main content

Operator Overloading -II

Let us consider some special cases of operator overloading

Overloading of subscript operator:
 
Subscript operator ([]) can be overloaded to access the dynamically allocated array elements within an object. Using subscript operator, we can treat these like a POD array and access ith element of the array using obj[i]
 
class Arr
{
 int *arr;
 int size;
public:
 int& operator [](int n) ;
 int operator[](int n) const;
/****code *****/
};

int &Arr::operator [](int index)
{
 return arr[index];
}

int Arr::operator [](int index) const
{
 return arr[index];
}
int main()
{
 Arr obj(10);
 for(int i=0;i<10;i++)
    obj[i] = i*i;
 for(int i=0;i<10;i++)
    cout<<arr[i]<<" ";
}

Output
    0 1 4 9 16 25 36 49 64 81


Why do we have two functions for this operator?  Is it allowed? Is it necessary?

const version of [] operator function is written so that constant objects can also access array elements. Non-constant version is helpful in modifying the array elements. Ideally you can use const function for displaying the elements and non-const version for setting values to these elements.

But we have to make sure that non-const version of [] function returns a reference, so that you can assign values to elements. Remember that a function returning a reference can be assigned a value.

Increment and Decrement operators

Increment and decrement operators have prefix and postfix versions for PODs. a++ and ++a.  So how do we overload these operators with two versions for objects?


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

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
class Number
{
 int num;
public:
 Number & operator++();/*prefix version*/
 Number operator++(int a);/*postfix version*/
/****code***/
};
Number & Number::operator++()
{
 num++;
 return *this;
}

Number Number::operator++(int dummy)
{
 Number temp = *this;
 num++;
 return temp;
}

int main()
{
 Number obj(9);
 Number obj2(1000);
 obj2 = ++obj;/*calls prefix*/
 obj = obj2++;/*calls postfix*/
}

In line 26, obj2 is assigned to prefix increment of obj. So obj2 will become 10. In line 27, we are using postfix ++ operator.   

obj2 is  is assigned to obj first and then is incremented. So obj becomes 10 and obj2 will be 11.

 Overloading new operator:


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

void *Number::operator new(size_t bytes)
{
 void *ptr = malloc(nbytes);
 return ptr;
}
void Number::operator delete(void *ptr)
{
 free(ptr);
}
 

Note that compiler provided new operator will be sufficient in most situations. You need to 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 streams.



These should be overloaded as non-member functions  because their first parameter will not be the object of the given class.  

>> must have istream object as first parameter and << must have ostream object as first parameter.

These two operator functions must return reference to iostream objects in order to use chaining in i/o operation. And it is necessary to use second parameter also as reference parameter in extraction operator as the function modifies the object.

class Number
{
 int num;
public: 
 friend ostream & operator <<(ostream& out, Number & obj);
 friend istream & operator >>(istream& in, Number & obj);
/****code***/
};

ostream & operator <<(ostream& out, Number & obj)
{
 out<<obj.num;
 return out;
}

istream & operator >>(istream& in, Number & obj)
{
 in>>obj.num;
 return in;
}

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:

These operator functions convert objects to other PODs or other type of objects. They are written without a return type. Instead, return type is the name of the operator. For example, to convert object to int, we  write an overloaded operator with name int and no return type.

class Number
{
 int a;
public:
 operator int()/*Converts Number to int*/
 {
 return a;
 }
/****code*****/
};
int main()
{
 Number obj(100);
 int m = obj;
/* uses int conversion operator */
 cout<<m;
}
 
Function call operator:


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

class Cube
{
public:
int operator ()(int n)
{
 return n*n*n;
}
};
int main()
{
 Cube cobj;
 int m = cobj(10);/*this cubes 10 and returns 1000*/
 cout<<m;
}

Output
1000

Overloading of assignment operator:


Compiler provides overloaded assignment operator function for a class which copies an object to another byte by byte. If your class does not use dynamic memory at all, then compiler provided assignment operator would be sufficient.

But if the class uses dynamic memory you have to write your own assignment operator because you need  a deep copy.

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

There is one more problem however. What if you use a statement which ultimately becomes self assignment because of references as shown below?

Integer obj1(10);
Integer &obj2 = obj1;
obj2= obj1;//self assignment

In this case, if you delete memory, all hell breaks loose.

To avoid this problem, check for self assignment, then delete memory, allocate new memory and copy elements.

class Arr
{
 int *arr;
 int n;
public:
 A& operator =(const A &obj1);
/****code *****/
};
A& A::operator =(const A & obj1)
{
 if(this !=&obj1)/*self assignment?*/
 {
 delete arr;
 arr = new int[obj1.n];
 for(int i=0;i<n;i++)
 arr[i] = obj1.arr[i];
 }
 return *this;
}

Here the operator function checks if there is self assignment by using this !=&obj1

Comments

Popular posts from this blog

Ten questions in C/C++

Let us see some questions in C and C++ Write printf statement in C to print - I got 98% in Maths Can you execute a function before main() in C? If yes, how is it done? Can you write a program to find if a number is even without using modulo operator? How do you define a data member which is common to all objects of a class in C++? Can we have a single constructor for a class, but still create objects from the class passing zero/one and two parameters? What problems might occur if a class has no default constructor? Is the following statement correct? fprintf(stdout,"Hello world");   Why do we use the following statement in C++ program? using namespace std;  Can you write a single statement to check if the number is a power of 2?  What does the following statement mean in C/C++?4 if(a) b++;    So we have 10 questions. How many of these can you answer?   Do you need more questions in C and C++?    You can find t...

Find the error in C++ program

This C++ program is not compiling. What do you think is the error with the program? #include<iostream> using namespace std; int main() {    int arr[10];    arr={1,2,3,4,5,6,7,8};    cout<<"arr[0]="<<arr[0];    return 0; } Is the error due to Not using printf Initialising the array with only 8 elements instead of 10 Initialising array in the next statement instead of in definition. None of the above  Now if you like this question, there are plenty more questions like this and programs and notes in my app Simplified C++. Download the Simplif ied C++   by Hegdeapps now By the way the correct answer is (3)

Basics of C++

Let us talk about some basics of the language.  Identifiers  All variables and functions and objects need a name - they need identifiers. Identifiers in C++ need to follow some simple rules      They need to start with either a-z/A-Z or _ (underline)      They can contain only alphabets, digits or underline      They need to be unique in their scope      They can not be keywords Examples of some bad identifiers    1var    sum of numbers    int Data types :  C++ has the following basic data types. We will talk about classes and objects later     int     float     char     double     bool int An int data type is used to store integer values. e.g.   int a=10; int b = -100;   float and double  are used to store real numbers. double ...