UNIT-3
Functions & Operator Overloading
If we create two or more members having the same name but different in number or type of parameter, it is known as C++ overloading. In C++, we can overload:
- methods,
- constructors, and
- indexed properties
It is because these members have parameters only.
Types of overloading in C++ are:
- Function overloading
- Operator overloading
Fig 1 - Overloading
Function Overloading is defined as the process of having two or more function with the same name, but different in parameters is known as function overloading in C++. In function overloading, the function is redefined by using either different types of arguments or a different number of arguments. It is only through these differences compiler can differentiate between the functions.
The advantage of Function overloading is that it increases the readability of the program because you don't need to use different names for the same action.
C++ Function Overloading Example
Let's see the simple example of function overloading where we are changing number of arguments of add() method.
// program of function overloading when number of arguments vary.
- #include <iostream>
- using namespace std;
- class Cal {
- public:
- static int add(int a,int b){
- return a + b;
- }
- static int add(int a, int b, int c)
- {
- return a + b + c;
- }
- };
- int main(void) {
- Cal C; // class object declaration.
- cout<<C.add(10, 20)<<endl;
- cout<<C.add(12, 20, 23);
- return 0;
- }
Output:
30
55
Let's see the simple example when the type of the arguments vary.
// Program of function overloading with different types of arguments.
- #include<iostream>
- using namespace std;
- int mul(int,int);
- float mul(float,int);
- int mul(int a,int b)
- {
- return a*b;
- }
- float mul(double x, int y)
- {
- return x*y;
- }
- int main()
- {
- int r1 = mul(6,7);
- float r2 = mul(0.2,3);
- std::cout << "r1 is : " <<r1<< std::endl;
- std::cout <<"r2 is : " <<r2<< std::endl;
- return 0;
- }
Output:
r1 is : 42
r2 is : 0.6
Function Overloading and Ambiguity
When the compiler is unable to decide which function is to be invoked among the overloaded function, this situation is known as function overloading.
When the compiler shows the ambiguity error, the compiler does not run the program.
Causes of Function Overloading:
- Type Conversion.
- Function with default arguments.
- Function with pass by reference.
Fig 2 – Causes of ambiquity
- Type Conversion:
Let's see a simple example.
- #include<iostream>
- using namespace std;
- void fun(int);
- void fun(float);
- void fun(int i)
- {
- std::cout << "Value of i is : " <<i<< std::endl;
- }
- void fun(float j)
- {
- std::cout << "Value of j is : " <<j<< std::endl;
- }
- int main()
- {
- fun(12);
- fun(1.2);
- return 0;
- }
The above example shows an error "call of overloaded 'fun(double)' is ambiguous". The fun(10) will call the first function. The fun(1.2) calls the second function according to our prediction. But, this does not refer to any function as in C++, all the floating point constants are treated as double not as a float. If we replace float to double, the program works. Therefore, this is a type conversion from float to double.
- Function with Default Arguments
Let's see a simple example.
- #include<iostream>
- using namespace std;
- void fun(int);
- void fun(int,int);
- void fun(int i)
- {
- std::cout << "Value of i is : " <<i<< std::endl;
- }
- void fun(int a,int b=9)
- {
- std::cout << "Value of a is : " <<a<< std::endl;
- std::cout << "Value of b is : " <<b<< std::endl;
- }
- int main()
- {
- fun(12);
- return 0;
- }
The above example shows an error "call of overloaded 'fun(int)' is ambiguous". The fun(int a, int b=9) can be called in two ways: first is by calling the function with one argument, i.e., fun(12) and another way is calling the function with two arguments, i.e., fun(4,5). The fun(int i) function is invoked with one argument. Therefore, the compiler could not be able to select among fun(int i) and fun(int a,int b=9).
- Function with pass by reference
Let's see a simple example.
- #include <iostream>
- using namespace std;
- void fun(int);
- void fun(int &);
- int main()
- {
- int a=10;
- fun(a); // error, which f()?
- return 0;
- }
- void fun(int x)
- {
- std::cout << "Value of x is : " <<x<< std::endl;
- }
- void fun(int &b)
- {
- std::cout << "Value of b is : " <<b<< std::endl;
- }
The above example shows an error "call of overloaded 'fun(int&)' is ambiguous". The first function takes one integer argument and the second function takes a reference parameter as an argument. In this case, the compiler does not know which function is needed by the user as there is no syntactical difference between the fun(int) and fun(int &).
Operator overloading is a compile-time polymorphism in which the operator is overloaded to provide the special meaning to the user-defined data type. Operator overloading is used to overload or redefines most of the operators available in C++. It is used to perform the operation on the user-defined data type. For example, C++ provides the ability to add the variables of the user-defined data type that is applied to the built-in data types.
The advantage of Operators overloading is to perform different operations on the same operand.
Operator that cannot be overloaded are as follows:
- Scope operator (::)
- Sizeof
- member selector(.)
- member pointer selector(*)
- ternary operator(?:)
Syntax of Operator Overloading
- return_type class_name : : operator op(argument_list)
- {
- // body of the function.
- }
Where the return type is the type of value returned by the function.
class_name is the name of the class.
operator op is an operator function where op is the operator being overloaded, and the operator is the keyword.
Rules for Operator Overloading
- Existing operators can only be overloaded, but the new operators cannot be overloaded.
- The overloaded operator contains atleast one operand of the user-defined data type.
- We cannot use friend function to overload certain operators. However, the member function can be used to overload those operators.
- When unary operators are overloaded through a member function take no explicit arguments, but, if they are overloaded by a friend function, takes one argument.
- When binary operators are overloaded through a member function takes one explicit argument, and if they are overloaded through a friend function takes two explicit arguments.
C++ Operators Overloading Example
Let's see the simple example of operator overloading in C++. In this example, void operator ++ () operator function is defined (inside Test class).
// program to overload the unary operator ++.
- #include <iostream>
- using namespace std;
- class Test
- {
- private:
- int num;
- public:
- Test(): num(8){}
- void operator ++() {
- num = num+2;
- }
- void Print() {
- cout<<"The Count is: "<<num;
- }
- };
- int main()
- {
- Test tt;
- ++tt; // calling of a function "void operator ++()"
- tt.Print();
- return 0;
- }
Output:
The Count is: 10
Let's see a simple example of overloading the binary operators.
// program to overload the binary operators.
- #include <iostream>
- using namespace std;
- class A
- {
- int x;
- public:
- A(){}
- A(int i)
- {
- x=i;
- }
- void operator+(A);
- void display();
- };
- void A :: operator+(A a)
- {
- int m = x+a.x;
- cout<<"The result of the addition of two objects is : "<<m;
- }
- int main()
- {
- A a1(5);
- A a2(4);
- a1+a2;
- return 0;
- }
Output:
The result of the addition of two objects is: 9
Key takeaway
If we create two or more members having the same name but different in number or type of parameter, it is known as C++ overloading. In C++, we can overload:
- methods,
- constructors, and
- indexed properties
It is because these members have parameters only.
In C++, constructor is a special method which is invoked automatically at the time of object creation. It is used to initialize the data members of new object generally. The constructor in C++ has the same name as class or structure.
There can be two types of constructors in C++.
- Default constructor
- Parameterized constructor
A constructor which has no argument is known as default constructor. It is invoked at the time of creating object.
Let's see the simple example of C++ default Constructor.
- #include <iostream>
- using namespace std;
- class Employee
- {
- public:
- Employee()
- {
- cout<<"Default Constructor Invoked"<<endl;
- }
- };
- int main(void)
- {
- Employee e1; //creating an object of Employee
- Employee e2;
- return 0;
- }
Output:
Default Constructor Invoked
Default Constructor Invoked
A constructor which has parameters is called parameterized constructor. It is used to provide different values to distinct objects.
Let's see the simple example of C++ Parameterized Constructor.
#include <iostream>
using namespace std;
class Employee {
public:
int id;//data member (also instance variable)
string name;//data member(also instance variable)
float salary;
Employee(int i, string n, float s)
{
id = i;
name = n;
salary = s;
}
void display()
{
cout<<id<<" "<<name<<" "<<salary<<endl;
}
};
int main(void) {
Employee e1 =Employee(101, "Sonoo", 890000); //creating an object of Employee
Employee e2=Employee(102, "Nakul", 59000);
e1.display();
e2.display();
return 0;
}
Output:
101 Sonoo 890000
102 Nakul 59000
Key takeaway
In C++, constructor is a special method which is invoked automatically at the time of object creation. It is used to initialize the data members of new object generally. The constructor in C++ has the same name as class or structure.
There can be two types of constructors in C++.
- Default constructor
- Parameterized constructor
A destructor works opposite to constructor; it destructs the objects of classes. It can be defined only once in a class. Like constructors, it is invoked automatically.
A destructor is defined like constructor. It must have same name as class. But it is prefixed with a tilde sign (~).
Note: C++ destructor cannot have parameters. Moreover, modifiers can't be applied on destructors.
C++ Constructor and Destructor Example
Let's see an example of constructor and destructor in C++ which is called automatically.
- #include <iostream>
- using namespace std;
- class Employee
- {
- public:
- Employee()
- {
- cout<<"Constructor Invoked"<<endl;
- }
- ~Employee()
- {
- cout<<"Destructor Invoked"<<endl;
- }
- };
- int main(void)
- {
- Employee e1; //creating an object of Employee
- Employee e2; //creating an object of Employee
- return 0;
- }
Output:
Constructor Invoked
Constructor Invoked
Destructor Invoked
Destructor Invoked
Key takeaway
A destructor works opposite to constructor; it destructs the objects of classes. It can be defined only once in a class. Like constructors, it is invoked automatically.
A destructor is defined like constructor. It must have same name as class. But it is prefixed with a tilde sign (~).
Note: C++ destructor cannot have parameters. Moreover, modifiers can't be applied on destructors.
- Friend function using operator overloading offers better flexibility to the class.
- These functions are not a members of the class and they do not have 'this' pointer.
- When you overload a unary operator you have to pass one argument.
- When you overload a binary operator you have to pass two arguments.
- Friend function can access private members of a class directly.
Syntax:
friend return-type operator operator-symbol (Variable 1, Varibale2)
{
//Statements;
}
Example : Program demonstrating Unary operator overloading using Friend function
#include<iostream>
using namespace std;
class UnaryFriend
{
int a=10;
int b=20;
int c=30;
public:
void getvalues()
{
cout<<"Values of A, B & C\n";
cout<<a<<"\n"<<b<<"\n"<<c<<"\n"<<endl;
}
void show()
{
cout<<a<<"\n"<<b<<"\n"<<c<<"\n"<<endl;
}
void friend operator-(UnaryFriend &x); //Pass by reference
};
void operator-(UnaryFriend &x)
{
x.a = -x.a; //Object name must be used as it is a friend function
x.b = -x.b;
x.c = -x.c;
}
int main()
{
UnaryFriend x1;
x1.getvalues();
cout<<"Before Overloading\n";
x1.show();
cout<<"After Overloading \n";
-x1;
x1.show();
return 0;
}
Output:
Values of A, B & C
10
20
30
Before Overloading
10
20
30
After Overloading
-10
-20
-30
In the above program, operator – is overloaded using friend function. The operator() function is defined as a Friend function. The statement -x1 invokes the operator() function. The object x1 is created of class UnaryFriend. The object itself acts as a source and destination object. This can be accomplished by sending reference of an object. The object x1 is a reference of object x. The values of object x1 are replaced by itself by applying negation.
Key takeaway
- Friend function using operator overloading offers better flexibility to the class.
- These functions are not a members of the class and they do not have 'this' pointer.
- When you overload a unary operator you have to pass one argument.
- When you overload a binary operator you have to pass two arguments.
- Friend function can access private members of a class directly.
The binary operators take two arguments and following are the examples of Binary operators. You use binary operators very frequently like addition (+) operator, subtraction (-) operator and division (/) operator.
Following example explains how addition (+) operator can be overloaded. Similar way, you can overload subtraction (-) and division (/) operators.
#include <iostream>
using namespace std;
class Box {
double length; // Length of a box
double breadth; // Breadth of a box
double height; // Height of a box
public:
double getVolume(void) {
return length * breadth * height;
}
void setLength( double len ) {
length = len;
}
void setBreadth( double bre ) {
breadth = bre;
}
void setHeight( double hei ) {
height = hei;
}
// Overload + operator to add two Box objects.
Box operator+(const Box& b) {
Box box;
box.length = this->length + b.length;
box.breadth = this->breadth + b.breadth;
box.height = this->height + b.height;
return box;
}
};
// Main function for the program
int main() {
Box Box1; // Declare Box1 of type Box
Box Box2; // Declare Box2 of type Box
Box Box3; // Declare Box3 of type Box
double volume = 0.0; // Store the volume of a box here
// box 1 specification
Box1.setLength(6.0);
Box1.setBreadth(7.0);
Box1.setHeight(5.0);
// box 2 specification
Box2.setLength(12.0);
Box2.setBreadth(13.0);
Box2.setHeight(10.0);
// volume of box 1
volume = Box1.getVolume();
cout << "Volume of Box1 : " << volume <<endl;
// volume of box 2
volume = Box2.getVolume();
cout << "Volume of Box2 : " << volume <<endl;
// Add two object as follows:
Box3 = Box1 + Box2;
// volume of box 3
volume = Box3.getVolume();
cout << "Volume of Box3 : " << volume <<endl;
return 0;
}
When the above code is compiled and executed, it produces the following result −
Volume of Box1 : 210
Volume of Box2 : 1560
Volume of Box3 : 5400
The unary operators operate on a single operand and following are the examples of Unary operators −
- The increment (++) and decrement (--) operators.
- The unary minus (-) operator.
- The logical not (!) operator.
The unary operators operate on the object for which they were called and normally, this operator appears on the left side of the object, as in !obj, -obj, and ++obj but sometime they can be used as postfix as well like obj++ or obj--.
Following example explain how minus (-) operator can be overloaded for prefix as well as postfix usage.
#include <iostream>
using namespace std;
class Distance {
private:
int feet; // 0 to infinite
int inches; // 0 to 12
public:
// required constructors
Distance() {
feet = 0;
inches = 0;
}
Distance(int f, int i) {
feet = f;
inches = i;
}
// method to display distance
void displayDistance() {
cout << "F: " << feet << " I:" << inches <<endl;
}
// overloaded minus (-) operator
Distance operator- () {
feet = -feet;
inches = -inches;
return Distance(feet, inches);
}
};
int main() {
Distance D1(11, 10), D2(-5, 11);
-D1; // apply negation
D1.displayDistance(); // display D1
-D2; // apply negation
D2.displayDistance(); // display D2
return 0;
}
When the above code is compiled and executed, it produces the following result −
F: -11 I:-10
F: 5 I:-11
Hope above example makes your concept clear and you can apply similar concept to overload Logical Not Operators (!).
Key takeaway
The binary operators take two arguments and following are the examples of Binary operators. You use binary operators very frequently like addition (+) operator, subtraction (-) operator and division (/) operator.
Following example explains how addition (+) operator can be overloaded. Similar way, you can overload subtraction (-) and division (/) operators.
You can overload the assignment operator (=) just as you can other operators and it can be used to create an object just like the copy constructor.
Following example explains how an assignment operator can be overloaded.
#include <iostream>
using namespace std;
class Distance {
private:
int feet; // 0 to infinite
int inches; // 0 to 12
public:
// required constructors
Distance() {
feet = 0;
inches = 0;
}
Distance(int f, int i) {
feet = f;
inches = i;
}
void operator = (const Distance &D ) {
feet = D.feet;
inches = D.inches;
}
// method to display distance
void displayDistance() {
cout << "F: " << feet << " I:" << inches << endl;
}
};
int main() {
Distance D1(11, 10), D2(5, 11);
cout << "First Distance : ";
D1.displayDistance();
cout << "Second Distance :";
D2.displayDistance();
// use assignment operator
D1 = D2;
cout << "First Distance :";
D1.displayDistance();
return 0;
}
When the above code is compiled and executed, it produces the following result −
First Distance : F: 11 I:10
Second Distance :F: 5 I:11
First Distance :F: 5 I:11
Key takeaway
You can overload the assignment operator (=) just as you can other operators and it can be used to create an object just like the copy constructor.
REFERENCE
1 Object-Oriented Programming with C++ by E. Balaguruswamy. (Tata McGraw-Hill) 6th Edition and onwards
2. Object oriented Programming with C++- by SouravSahay (Oxford) 2ndedition