C++ is a powerful and versatile backend programming language that offers a wide array of features to developers. operator overloading is another polymorphism feature in c++. Operator overloading is the mechanism of giving special meanings to an operator.
In other words, operator overloading refers to giving the normal c++ operators ( such as +, – , *, /, <=, += etc) additional meanings when they are applied to user defined data-types.
Table of Contents
Concept of Operator Overloading In C++
Defining Operator Overloading
Operator overloading is one of the many exciting features of the C++ language. It is an important technique that has enhanced the power of extensibility of C++. We have stated more than once that C++ tries to make the user-defined data types behave in much the same way as the built-in types. For instance, C++ permits us to add two variables of user-defined types with the same syntax that is applied to the basic types. This means that C++ can provide the operators with a special meaning for a data type. The mechanism of giving such special meanings to an operator is known as operator overloading.
What Operators we can Overload?
- Unary Operators (-, +, !, ~)
- Binary Operators or Arithmetic Operators (+, -, *, |, % )
- Relational / Comparison Operators ( <, >, <=, >=, != etc)
- Increment / Decrement Operators (++, — )
- Logical Operators ( &&, || )
- Comma Operator ( , )
- Pointer to Member ( – >)
- Operator Assignment ( +=, -=, &=, /=, %= )
What Operators we can not Overload?
- Ternary expression operator
- Scope Resolution Operator ( : : )
- Pre-processed symbol operator (#,##)
- Class member operators ( . )
- Size of operator (size of)
- Conditional operator(? 🙂
- Pointer to member operator (.*)
Rules of Operating Overloading
- Only the existing operators can be overloaded. New operators cannot be created
- The overloaded operators must have at least one user-defined operand.
- We cannot redefine the plus(+) operator to subtract one value from the other.
- Overloaded operators follow the syntax rule of the original operators.
- Friend function cannot be used to overload certain operators like =, ( ), [ ] , ->
- Some operators like the size of the operator(size of), membership operator ( . ), a pointer to a member operator ( .*), scope resolution operator ( : : ), conditional operator ( ? : ), etc cannot be overloaded.
- Binary operators such as +, -, *, / etc must explicitly return a value.
Unary Operator Overloading
Unary operators are those operators that operate (act) on a single operand. ++, — are unary operators. following unary operators can be overloaded.
- Unary plus(+) & unary minus(-)
- Increment(++) & decrement(–)
- One’s complement (2) operator
- Logical NOT (!)
- Address of ( & )
- Pointer deference (*)
Example
#include<iostream.h>
#include<conio.h>
class ICT {
int mark;
public:
void getmarks(int x) {
getmarks = x;
}
void display() {
cout<<mark="<<marks;
}
void operator ++() {
mark ++;
}
};
void main {
ICT s1;
s1++;
getch();
}
Binary Operator Overloading
This takes two operands while overloading. For example, c=a+b where a and b are two
operands. The following program illustrates overloading the + operator. following binary operators can be overloaded.
- Arithmetic Operators (+, -, *, |, % )
- Arithmetic assignment operator (+=, -=, *=, /=, %=)
- Relational operator (>, <, >=, <=, !=, ==)
Binary operator overloading is similar to unary operator overloading except that a binary operator overloading requires an additional parameter.
syntax
return type operator symbol (arg) {
// body of function
}
Example
#include<iostream.h>
#include<conio.h>
class complex {
float &x, y;
public:
complex() { }
complex (float real, float imag) {
x = real;
y= imag;
}
void display() {
cout<<x<<"+"<<y<<endl;
}
complex operator+(comlex c) {
complex sum;
sum.x = c.x+x;
sum.y = c.y+y;
return sum;
}
};
void main() {
complex c1,c2,c3;
c1=complex(2,3);
c2=complex(7,12);
c3=c1+c2;
c1.display();
c2.display();
c3.display();
getch();
}
Return types in the overloading function
When multiple definitions for the same function name in the same scope and the definition of the function must differ from each other by the types and/or the number of arguments in the argument list is known as return types in the overloading function. You cannot overload function declarations that differ only by return type.
The function overloading is the compile time polymorphism. It checks the function signature. If the signatures are not the same, then they can be overloaded. The return type of a function does not create any effect on function overloading. The same function signature with different return types will not be overloaded.
Following is the example where the same function print() is being used to print different data types
#include <iostream>
using namespace std;
class printData {
public:
void print(int i) {
cout << "Printing int: " << i << endl;
}
void print(double f) {
cout << "Printing float: " << f << endl;
}
void print(char* c) {
cout << "Printing character: " << c << endl;
}
};
int main(void) {
printData pd;
pd.print(5); // Call print to print integer
pd.print(500.263); // Call print to print float
pd.print("Hello C++"); // Call print to print character
return 0;
}
--------------------
Output
Printing int: 5
Printing float: 500.263
Printing character: Hello C++
Manipulation String using Operator Overloading
ANSI C implements strings using character arrays, pointers and string functions. There are no operators for manipulating the strings. One of the main drawbacks of string manipulations in C is that whenever a string is to be copied, the programmer must first determine its length and allocate the required amount of memory.
Although these limitations exist in C++ as well, it permits us to create our own definitions of operators that can be used to manipulate the strings very much similar to the decimal numbers. (Recently, ANSI C++ committee has added a new class called string to the C++ class library that supports all kinds of string manipulations.
For example, we shall be able to use statements like
string3 = string1+ string2; if(string> string2) string = string1;
Strings can be defined as class objects which can be then manipulated like the built-in types. Since the strings vary greatly in size, we use new to allocate memory for each string and a pointer variable to point to the string array. Thus we must create string objects that can hold these two pieces of information, namely, length and location which are necessary for string manipulations.
A typical string class will look as follows:
class string { char *p: // pointer to string int len; // length of string public: ............... // member functions ............... // to initialize and ............... // manipulate strings };
String operator overloading using + operator.
#include<iostream.h>
#include<conio.h>
class contact {
char str[40];
public:
contact() {
strcpy(str," ");
}
contact(chat * mystr) {
str cpy(str,mystr);
}
void display() {
cout<<str;
}
contact operator +(contact s) {
contact temp;
temp = str;
strcat(temp.str,s.str);
return temp;
}
};
void main() {
contact s1 = "TECH";
contact s2= "CODE";
contact s3;
s3 = s1+s2;
s1.display();
cout<<"+";
s2.display();
cout<<"=";
s3.display();
getch();
}
New and Delete Operator Overloading
The new and delete operator can also be overloaded like other operators in C++. new and delete operators can be overloaded globally or they can be overloaded for specific classes.
Sntax for new operator overloading
void * operator new(size_t size);
Syntax for delete operator overloading
void operator delete (void*);
Example of Program
#include<iostream.h>
#include<conio.h>
using namespace std;
class student {
string name;;
int age;
public:
strudent {
cout<<"Constructor is called \n"'
}
student (string name, int age) {
this -> name = name;
this -> age = age;
}
void display() {
cout<<"Name"<<name<<endl;
cout<<"Age"<<age<<endl;
}
void * operator new (size_t size) {
cout<<"overloading new operator with size:"<<size<<endl;
void* p = : : new student();
return *p;
}
void operator delete(void *p) {
{
cout<<"overloading delete operator"<<endl;
free(p);
}
};
int main() {
student *p = new student ("Yash", 24);
p-> display();
delete p;
}
};
Output
Overloading new operator with size: 16
Constructor is called
Name: Yash
Age: 24
overloading delete operator
Data Conversion or Type Conversion
The process of converting the data type of a value in another data type is known as data type conversion. for example.
int x; float y = 15.215; x = y;
In this example, float variable y is converted to an integer before its value is assigned to x.
There are three types of data type conversion.
- Conversion from basic type to class type
- Conversion from class type to basic type
- Conversion from one class type to another class type
Conversion from basic type to class type
The conversion from basic to class type can be done by using the constructor.
For Example
#include <iostream.h>
#include <conio.h>
class distance
{
int feet ;
float inches ;
public: distance (float mtr)
{
float f=3.28*mtr ;
feet=int(f) ;
inches=12*(f-feet) ;
}
void show( )
{
cout<< “distance is”<<endl ;
cout<<feet<< “\’-”<<inches<<’\”’<<endl ;
}
};
void main( )
{
clrscr( ) ;
float meter ;
cout<< “Enter a distance:” ;
cin>>meter ;
distance d1=meter ;
d1.show( ) ;
getch( ) ;
}
Output:
Enter a distance : 2.3
distance is
7’ – 6.527996”
Conversion from class type to basic type
By the constructor we cannot convert class to basic type. For converting class type to
basic type, we can define a overloaded casting operator in C++.
The casting operator function should satisfy the following conditions:
- It must be a class member.
- It must not specify a return type
- It must not have any arguments.
The general format of an overloaded casting operator function.
operator typename() { ........... ........... (Function statements) ........... }
Example
#include <iostream.h>
#include <conio.h>
class distance
{
int feet ;
float inches ;
public: distance (int f, float i)
{
feet=f ; inches=i ;
}
void show( )
{
cout<<feet<< “\’=”<<inches<<’\”’;
}
operator float( ) {
float ft=inches12 ;
ft=ft+feet ;
return(ft/3.28) ;
}
};
void main( )
{
distance d1(3, 3.36) ;
float m=d1 ;
clrscr( ) ;
cout<< “distance in meter:”<<m<<endl ;
cout<< “distance in feet and inches:”<<endl ;
d1.show( ) ;
getch( ) ;
}
Output:
distance in meter : 1.0
distance in feet and inches:
3’ – 3.36”
Conversion from one class type to another class type
We can convert one class(object) to another class type as follows: object of X = object of Y.
X and Y both are different types of classes. The conversion takes place from class Y to Class
A, therefore, Y is the source class and X is the destination class.
Class type one to another class can be converted in the following way:
- By constructor
- By conversion function
By constructor
When the conversion routine is in the destination class, it is commonly implemented as a constructor.
// example of convert polar co-ordinate to rectangle co-ordinate
#include <math.h>
#include <iostream.h>
#include <conio.h>
class polar
{
float rd ;
float ang ;
public: polar( )
{
rd=0.0 ; ang=0.0
}
polar (float r, float a) {
ra=r ; ang=a ;
}
float getrd( )
{
return(rd) ;
}
float getang( )
{
return(ang);
}
void showpolar( )
{
cout<<rd<< “,”<<ang<<endl ;
}
} ;
class rec
{
float x ;
float y ;
public: rec( ) {x=0.0 ; y=0.0 ;}
rec (float xco, float yco)
{x=xco ; y=yco ; }
rec (polar p)
{ float r=p.getrd( ) ;
float a=p.getamg( ) ;
x=r*cos(a) ;
y=r*sin(a) ;
}
void showrec( ) {
cout<<x<< “,”<<y<<endl ;
}
} ;
void main( ) {
rec r1 ;
polar p1(2.0, 90.0) ;
clrscr( ) ;
r1=p1 ;
cout<< “polar co.”<<endl ; p1.showpolar( ) ;
cout<< “rec co. :”<<endl ;
r1.showrec( ) ;
getch( ) ;
}
Output:
polar co. : 2.0, 90.0
rec co. : 0.0, 2.0
By conversion function
When the conversion routine is in the source class, it is implemented as a conversion
function.
// example of convert polar co-ordinate to rec co-ordinate
#include <math.h>
#include <iostream.h>
#include <conio.h>
class rec {
float x ;
float y ;
public: rec( )
{
x=0.0 ;
y=0.0 ;
}
rec (float xw, float yw)
{
x=xw ;
y=yw ;
}
Conclusion
Operator overloading in C++ empowers developers to create more expressive and efficient code by extending the capabilities of operators for user-defined types. It’s a powerful tool that enhances the flexibility and readability of code, making it an essential feature for designing robust and scalable applications in C++. For a more comprehensive understanding of operator overloading in C++, here is useful resources: Tutorialspoint
FAQs
What are the main benefits of using Operator Overloading In C++?
Operator overloading empowers developers by allowing them to redefine the behavior of operators, leading to more natural and intuitive code. It improves code readability, reduces complexity, and enhances efficiency in C++ programming.
Can I overload all operators in C++?
No, not all operators can be overloaded in C++. A few operators such as the scope resolution operator (::), member selector operator (.), and ternary conditional operator (?:) cannot be overloaded.
How does Operator Overloading differ from Function Overloading?
Operator overloading deals specifically with redefining the behavior of operators, enabling them to work with user-defined types. Function overloading, on the other hand, involves defining multiple functions with the same name but different parameters, allowing for different functionalities based on the arguments.