Operator Overloading Notes

Download as pdf or txt
Download as pdf or txt
You are on page 1of 16

Operator Overloading

Operator Overloading ...........................................................................................1


Why Overload Operators? .....................................................................................1
Use of friend functions in Operator loading. .............................................................1
Introducing Operator Overloading ..........................................................................1
Operator Overloading Rules ..................................................................................2
Overloading Unary Operators ................................................................................2
Using Simple Prefix Operators.......................................................................2
Using Prefix and Postfix Increment and Decrement Operators .....................3
Summary of Overloadable Operators ......................................................................5
Overloading Binary Operators ................................................................................8
Using a Friend Operator Function for Binary Operator Overloading ..........................10
Overloading the Function Call Operator ......................................................12
Overloading the Class Member Access Operator ....................................................13
Overloading the Comma Operator ........................................................................13
Assignments .....................................................................................................15
Answers .................................................................. Error! Bookmark not defined.

Operator Overloading

C++ allows you to redefine the meanings of operators, such as +, -, and =, for your classes.
Many object-oriented languages do not provide this capability, so you might be tempted to
disregard its usefulness in C++. However, it can be beneficial for making your classes
behave similarly to built-in types such as ints and doubles. It is even possible to write
classes that look like arrays, functions, or pointers!

Why Overload Operators?

The reasons vary for the different operators, but the general guiding principle is to make your
classes behave like built-in types. The closer your classes are to built-in types, the easier
they will be for clients to use. For example, if you want to write a class to represent fractions,
it's quite helpful to have the ability to define what +, -, *, and / mean when applied to objects
of that class.

Use of friend functions in Operator loading.

We might require a function to manipulate objects of two distinct classes. Friend function
enables us to create a function as a friend of a class. This function can access the private
and protected members of the class. Both global functions and member functions of other
classes can be made a friend of the class.

Introducing Operator Overloading

Operator overloading is used to make user-defined data types closer to basic data types so
that user-defined data types can be part of a mathematical expression. For example, you
can use the addition (+) operator to add two integers: float or double values. The plus
operator can be overloaded to add two objects, as shown below:
myclass obj1, obj2, obj3;
obj3 = obj1 + obj2;
Operator overloading is used to increase the functionality of the existing operators of C++ so
that they are applied to user-defined data types rather than just being limited to basic data
types.

Operators can be classified as two types based on the operands:


 Unary operators: Uses an operand. For example, the increment and decrement
operator.
 Binary operators: Uses two operands such as an addition (+), subtraction (-), and
multiplication (*) operator.

Operator Overloading Rules


 You cannot add new operator symbols. Only those operators that are predefined in
c++ language can be overloaded.
 The overloaded operator must have at least one operand that is of user-defined type.
 The basic meaning of an operator can’t be changed. That is we can’t redefine the plus
operator for subtract one from another.
 There are a few operators that you cannot overload, such as . , .*, ::, ?: . The operators
that you can't overload are usually not those you would care to overload anyway, so we
don't think you'll find this restriction limiting.
 When using binary operators overloaded though a member function, the left-hand
operand must be an object of the relevant class.
 Unary operators overloaded by means of a member function, take no explicit
arguments and return no explicit values. But those overloaded by manes of a friend
function take one reference argument.
 You cannot change the precedence or associativity of the operator. These rules
determine in which order operators are evaluated in a statement. Again, this constraint
shouldn't be cause for concern in most programs because there are rarely benefits to
changing the order of evaluation.

Some of the operators already mean two different things. For example, the – operator can
be used as a binary operator, as in x = y - z or as a unary operator, as in x = -y;. The *
operator can be used for multiplication or for dereferencing a pointer. The << operator is the
insertion operator or the left-shift operator, depending on context. You can overload both
meanings of operators with dual meanings.

The syntax to create a member operator function is as shown below:


<return_type> operator<operator_symbol> (<argument_list>)
{
//body of the function
}

Overloading Unary Operators

Unary operators are operators that take one operand. They are classified as simple prefix
operators, increment and decrement operators, and type cast operators.

Using Simple Prefix Operators

A simple prefix operator such as negation(!) and negative(-) operator may be defined by
a member function that takes no parameters, as shown below:

#include<iostream.h>
class INTEGER
{
private:
int x;
public:
INTEGER(int p=0) //Constructor
{
x=p;
}
//other functions
INTEGER operator -() //Overloaded the negative sign operator
{
INTEGER obj;
obj.x = -x;
return obj;
}
void display()
{
cout<<"x="<<x<<endl;
}
};//end of INTEGER class

void main()
{
INTEGER k=40; //Object of INTEGER class and 40 is passed as
//parameter

k.display ();
INTEGER m=-k; //Object of INTEGER class and -k is passed as parameter
m.display ();
}

INTEGER m=-k; //Object of INTEGER class and -k is passed as parameter


In the above statement, the compiler resolves –k as k.operator !().

Using Prefix and Postfix Increment and Decrement Operators

The compiler distinguishes the prefix and postfix increment and decrement operators. When
you use the prefix and postfix operators for incrementing an object the syntax is as follows:
++<object_name>; //Using prefix increment operator
<object_name>++; //Using postfix increment operator

In the above syntax, both the statements are translated by the compiler using:
<object_name> operator ++();

The compiler distinguishes the prefix and postfix operators by the use of a dummy integer to
all postfix unary operators as shown below:
<object_name>++; /*Resolved by compiler as <object_name>.operator ++(0)*/
To overload the prefix and postfix increment operators you need to define the member
operator functions such as:

<class_name> operator ++() //Overloading prefix increment operator


{
//function body
return <class_name_object>
}
<class_name> operator ++(int) //Overloading postfix increment operator
{
//Function body
return <class_name_object>
}

To overload the prefix and postfix decrement operators you need to define the member
operator functions such as:
<class_name> operator --() //Overloading prefix decrement operator
{
//function body
return <class_name_object>
}
<class_name> operator --(int) //Overloading postfix decrement operator
{
//Function body
return <class_name_object>
}

Example:

#include<iostream.h>
class INTEGER
{
private:
int x;
public:
INTEGER(int p=0) //Constructor
{
x=p;
}
void display()
{
cout<<"x="<<x<<endl;
}

INTEGER operator ++() //Overloading prefix operator


{
cout<<"prefix"<<endl;
INTEGER obj;
obj.x = ++x;
return obj;
}

INTEGER operator ++(int p)//Overloading postfix operator


{
cout<<"postfix"<<endl;
INTEGER obj;
obj.x = x++;
return obj;
}

};//end of INTEGER class

void main()
{
INTEGER k=40;
k.display ();
++k;
k.display ();
INTEGER k1= k++;
k1.display ();
k.display ();
}

Summary of Overloadable Operators

The following table lists all of the operators that you can overload, specifies whether they
should be methods of the class or global friend functions, summarizes when you should (or
should not) overload them, and provides sample prototypes, showing the proper return
values.

In this table, T is the name of the class for which the overloaded operator is written, and E is
a different type (not the name of the class).
Operator Name or Method or When to Sample Prototype
Category Global Overload
Friend
Function
operator+ Binary Global friend Whenever friend const T
operator- arithmetic function you want to operator+(const T&,
recommende provide const T&);
operator* d these
operator/ operations
for your
operator% class
operator- Unary Method Whenever const T operator-()
operator+ arithmetic and recommende you want to const;
bitwise d provide
operator~ operators these
operations
for your
class
operator++ Increment and Method Whenever T& operator++();
operator-- decrement recommende you
d overload
binary + const T operator++(int);
and -
operator= Assignment Method Whenever T& operator=(const T&);
operator required you have
dynamically
allocated
memory in
the object
or want to
prevent
assignment
, as
described
in Chapter
9
operator+= Shorthand Method Whenever T& operator+=(const
operator-= arithmetic recommende you T&);
operator d overload
operator*/ assignments the binary
operator/= arithmetic
operators
operator%
=
operator<< Binary bitwise Global friend Whenever friend const T
operator>> operators function you want to operator<<(const T&,
recommende provide const T&);
operator& d these
operator| operations
operator^
operator<< Shorthand Method Whenever T& operator<<= (const
= bitwise recommende you T&);
operator>> operator d overload
= assignments the binary
bitwise
operator&= operators
operator|=
operator^=
operator< Binary Global friend Whenever friend bool
operator> comparison function you want to operator<(const T&,
operators recommende provide const T&);
operator<= d these
operator>= operations
operator==
operator<< I/O stream Global friend Whenever friend ostream
operator>> operators function you want to &operator<< (ostream&,
(insertion and recommende provide const T&);
extraction) d these
operations
friend istream
&operator>> (istream&,
T&);
operator! Boolean Member Rarely; use bool operator!() const;
negation function bool or
operator recommende void*
d conversion
instead
operator&& Binary Global friend Rarely friend bool
operator|| Boolean function operator&&(const T&
operators recommende lhs, const T& rhs);
d

friend bool
operator||(const T& lhs,
const T& rhs);
operator[] Subscripting Method When you E& operator[](int);
(array index) required want to
operator support
subscriptin const E& operator[](int)
g: in array- const;
like classes
operator() Function call Method When you Return type and
operator required want arguments can vary; see
objects to examples in this chapter
behave like
function
pointers
operator Memory Method When you void* operator
new allocation recommende want to new(size_t size)
operator routines d control throw(bad_alloc);
new[] memory
allocation
for your void* operator
classes new[](size_t size)
(rarely) throw(bad_alloc);
operator Memory Method Whenever void operator
delete deallocation recommende you delete(void* ptr) throw();
operator routines d overload
delete[] the
memory void operator
allocation delete[](void* ptr)
routines throw();
operator* Dereferencing Method Useful for E& operator*() const; E*
operator-> operators required for smart operator->() const;
operator-> pointers
Method
recommende
d for
operator*
operator& Address-of N/A Never N/A
operator
operator->* Dereference N/A Never N/A
pointer-to-
member
operator, Comma N/A Never N/A
operator
operator Conversion, or Method When you operator type() const;
type() cast, operators required want to
(separate provide
operator for conversion
each type) s from your
class to
other types

Overloading Binary Operators

Binary operators are operators that work on two operands, such as:
 Arithmetic operators: +, -, *, %, and /
 Arithmetic assignment operators: +=, -=, *=, /=, and %=
 Comparison operators: >, <, <=, >=, ==, and !=

Overloading a binary operator is similar to overloading a unary operator except that the
binary operator requires an additional parameter, as shown:
//Program overloads the +, -, <, and == operators
#include<iostream>
using namespace std;
class INTEGER
{
private:
int x;
public:
INTEGER(int p=0)
{
x=p;
}
INTEGER operator +(INTEGER &k) //Overloading + operator
{
INTEGER obj;
obj.x = x + k.x;
return obj;
}

INTEGER operator -(INTEGER &k) //Overloading - operator - binary


{
INTEGER obj;
obj.x = x - k.x;
return obj;
}

INTEGER operator -() //Overloading - operator uniary


{
INTEGER obj;
obj.x = -x;
return obj;
}

bool operator <(INTEGER &k) //Overloading < operator


{
bool status=x < k.x ;
return status;
}

bool operator ==(INTEGER &k) //Overloading == operator


{
bool status = (x==k.x) ;
return status;
}
operator int() //Typecast operator
{
return x;
}

//Function to display contents of INTEGER class


void display(void)
{
cout<<x<<endl;
return;
}
};

int main()
{
INTEGER i=50, j=90;
INTEGER k=i+j;
cout<<"Value in k after addition->";
k.display();
INTEGER m=j-i;
cout<<"Value in m after subtraction->";
m.display();
if (i<j)
cout<<" i is less than j"<<endl;
if (j==90)
cout<<" j is equal to 90"<<endl;
INTEGER g = -m;
g.display ();
return 0;
}

INTEGER d = 20 + a; //not executed


The above statements cannot be executed because the first argument is a constant and it does
not invoke the member function of the object

Using a Friend Operator Function for Binary Operator Overloading

#include<iostream.h>
class INTEGER
{
//Declaring friend functions

private:

int x;
public:
friend INTEGER operator +(int v,INTEGER o);
INTEGER(int p=0)
{
x=p;
}

INTEGER operator +(INTEGER &k) //Overloading + operator


{
INTEGER obj;
obj = x + k.x;
return obj;
}

INTEGER operator -(INTEGER &k) //Overloading - operator


{
INTEGER obj;
obj = x - k.x;
return obj;
}

bool operator <(INTEGER &k) //Overloading < operator


{
bool status=x < k.x ;
return status;
}
bool operator ==(INTEGER &k) //Overloading == operator
{
bool status = (x==k.x) ;
return status;
}
operator int() //Typecast operator
{
return x;
}

//Function to display contents of INTEGER class


void display(void)
{
cout<<x<<endl;
return;
}

};

INTEGER operator +(int t,INTEGER obj)


{
INTEGER o;

o.x = t + obj.x;
return o;

int main()
{
INTEGER i=50, j=90;
INTEGER k=i+j;
cout<<"Value in k after addition->";
k.display();
INTEGER m=j-i;
cout<<"Value in m after subtraction->";
m.display();
if (i<j)
cout<<" i is less than j"<<endl;
if (j==90)
cout<<" j is equal to 90"<<endl;

cout<<"After friend function call"<<endl;

INTEGER a=20;
INTEGER d = 20 + a;
d.display ();
return 0;

}
Overloading the Function Call Operator

When you overload the ( ) function call operator, you are not, per se, creating a new way to
call a function. Rather, you are creating an operator function that can be passed an arbitrary
number of parameters. Let's begin with an example. Given the overloaded operator function
declaration
double operator()(int a, float f, char *s);

and an object O of its class, then the statement


O(10, 23.34, "hi");

translates into this call to the operator( ) function.


O.operator()(10, 23.34, "hi");

In general, when you overload the ( ) operator, you define the parameters that you want to
pass to that function. When you use the ( ) operator in your program, the arguments you
specify are copied to those parameters. As always, the object that generates the call (O in
this example) is pointed to by the this pointer

//The object of chardata class handles string


//The function operator is used to extract a substring
#include<iostream>
#include<string>
using namespace std;
class chardata
{
private:
char *s;
public:
chardata(char *p=NULL)
{
s=p;
}

//Operator returns a substring, containing k characters


//starting from i

char *operator ()(int i, int k)


{
char *str=new char[k+1];
strncpy(str,&s[i-1],k);//C++ library function
str[k]='\0';
return str;
}
};
int main()
{
chardata k="CANADA";
cout<<"Original string in object k is CANADA"<<endl;
cout<<"Displaying k(2,3) ->";
cout<<k(2,3)<<endl;
return 0;
}

Overloading the Class Member Access Operator

The class member access operator represented by the -> symbol, is a unary operator. The
syntax is as follows:
object->element;
The operator->() function returns a pointer to an object of the class that the operator->()
operates upon. The element must be a member that is accessible within the object. You can
create an equivalence between object var1 and object->var1 by overloading the class member
access operator that returns the this pointer

Overloading the Comma Operator

You can overload C++'s comma operator. The comma is a binary operator, and like all
overloaded operators, you can make an overloaded comma perform any operation you want.
However, if you want the overloaded comma to perform in a fashion similar to its normal
operation, then your version must discard the values of all operands except the rightmost.
The rightmost value becomes the result of the comma operation. This is the way the comma
works by default in C++.

Here is a program that illustrates the effect of overloading the comma operator.
#include <iostream>
using namespace std;

class loc {
int longitude, latitude;
public:
loc() {}
loc(int lg, int lt) {
longitude = lg;
latitude = lt;
}

void show() {
cout << longitude << " ";
cout << latitude << "\n";
}

loc operator+(loc op2);


loc operator,(loc op2);
};

// overload comma for loc


loc loc::operator,(loc op2)
{
loc temp;

temp.longitude = op2.longitude;
temp.latitude = op2.latitude;
cout << op2.longitude << " " << op2.latitude << "\n";

return temp;
}

// Overload + for loc


loc loc::operator+(loc op2)
{
loc temp;

temp.longitude = op2.longitude + longitude;


temp.latitude = op2.latitude + latitude;

return temp;
}

int main()
{
loc ob1(10, 20), ob2( 5, 30), ob3(1, 1);

ob1.show();
ob2.show();
ob3.show();
cout << "\n";
ob1 = (ob1, ob2+ob2, ob3);

ob1.show(); // displays 1 1, the value of ob3

return 0;
}

This program displays the following output:


10 20
5 30
11

10 60
11
11

Notice that although the values of the left-hand operands are discarded, each expression is
still evaluated by the compiler so that any desired side effects will be performed.
Remember, the left-hand operand is passed via this, and its value is discarded by the
operator,( ) function. The value of the right-hand operation is returned by the function. This
causes the overloaded comma to behave similarly to its default operation. If you want the
overloaded comma to do something else, you will have to change these two features.

Assignments

1. Implement a string class using the specifications below.

Table 7-4: Member Functions of the string Class


Function Prototype Description
Size int size(); Returns the number of elements in
the string object.
Resize void resize(int n,[char]); Resizes the size of a string object by
n elements. The second argument is
optional and specifies the padding
character.
Assign string &assign(const string Assigns a part of the content of the
&obj, int from_pos, int string object or assigns a number of
no_of_elements); repeated characters.
string &assign(int n, char var);
Append string &append(const string Appends a character, pointer to a
&obj); character, a string object, or multiple
string &append(const string copies of a character to a string
&obj, int start_pos, int object.
no_char);
string &append(int
no_of_copies, char chr);
string &append(const char *ptr,
int no_chr);
Find first int find(const string &obj, int Finds the first occurrence of a single
occurrence pos=0)const; character or a string in a string object.
int find(const char *str, int
pos=0)const;
int find(const char *str, int pos,
int no_char)const;
int find(char str, int
pos=0)const;
Find last int rfind(const string &obj, int Finds the last occurrence of a single
occurrence pos=0)const; character or a string in a string object.
int rfind(const char *str, int
pos=0)const;
int rfind(char str, int
pos=0)const;
Replace string &replace(int pos_source, Finds and replaces a search string
int len_of_search, const string with the replace string.
&replace_str);
string &replace(int pos_source,
int len_of_search, char * string
&replace_str);
Substring string &substr(int pos=0, int Extracts a portion of the string
n=string::npos); contained in the string object.

2. Write a program for accessing class's public data member using object(not using pointer)
of the class and -> operator.
3. Overload the Subscript Operator []
4. Overload the function () Operator

You might also like