0% found this document useful (0 votes)
2 views14 pages

Polymorphism in Inheritance and Operator Overloading

The document discusses polymorphism in C++ inheritance, highlighting function overriding as a form of runtime and compile-time polymorphism. It also explains operator overloading, allowing operators to be redefined for user-defined types, and outlines which operators can and cannot be overloaded. Additionally, it covers early and late binding, demonstrating how function calls are resolved at compile time versus runtime.

Uploaded by

singhkv608
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
Download as pdf or txt
0% found this document useful (0 votes)
2 views14 pages

Polymorphism in Inheritance and Operator Overloading

The document discusses polymorphism in C++ inheritance, highlighting function overriding as a form of runtime and compile-time polymorphism. It also explains operator overloading, allowing operators to be redefined for user-defined types, and outlines which operators can and cannot be overloaded. Additionally, it covers early and late binding, demonstrating how function calls are resolved at compile time versus runtime.

Uploaded by

singhkv608
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
Download as pdf or txt
Download as pdf or txt
You are on page 1/ 14

Polymorphism in Inheritance

In Inheritance, we can redefine the base class member function in the


derived class. This type of inheritance is called Function Overriding.
Generally, in other programming languages, function overriding is runtime
polymorphism but in C++, we can do it at both runtime and complile time. For
runtime polymorphism, we have to use the virtual functions.
Example
// C++ program to demonstrate compile time function
// overriding

#include <iostream>
using namespace std;

class Parent {
public:
void GeeksforGeeks_Print()
{
cout << "Base Function" << endl;
}
};

class Child : public Parent {


public:
void GeeksforGeeks_Print()
{
cout << "Derived Function" << endl;
}
};

int main()
{
Child Child_Derived;
Child_Derived.GeeksforGeeks_Print();
return 0;
}

Output
Derived Function
Operator Overloading in C++
in C++, Operator overloading is a compile-time polymorphism. It is an idea of giving
special meaning to an existing operator in C++ without changing its original meaning.
In this article, we will further discuss about operator overloading in C++ with
examples and see which operators we can or cannot overload in C++.
C++ Operator Overloading
C++ has the ability to provide the operators with a special meaning for a data type,
this ability is known as operator overloading. Operator overloading is a compile-time
polymorphism. For example, we can overload an operator ‘+’ in a class like String so
that we can concatenate two strings by just using +. Other example classes where
arithmetic operators may be overloaded are Complex Numbers, Fractional Numbers,
Big integers, etc.
Example:
int a;
float b,sum;
sum = a + b;
Here, variables “a” and “b” are of types “int” and “float”, which are built-in data
types. Hence the addition operator ‘+’ can easily add the contents of “a” and “b”. This
is because the addition operator “+” is predefined to add variables of built-in data type
only.
Implementation:
// C++ Program to Demonstrate the
// working/Logic behind Operator
// Overloading
class A {
statements;
};

int main()
{
A a1, a2, a3;

a3 = a1 + a2;

return 0;
}

In this example, we have 3 variables “a1”, “a2” and “a3” of type “class A”. Here we
are trying to add two objects “a1” and “a2”, which are of user-defined type i.e. of type
“class A” using the “+” operator. This is not allowed, because the addition operator
“+” is predefined to operate only on built-in data types. But here, “class A” is a user-
defined type, so the compiler generates an error. This is where the concept of
“Operator overloading” comes in.
Now, if the user wants to make the operator “+” add two class objects, the user has to
redefine the meaning of the “+” operator such that it adds two class objects. This is
done by using the concept of “Operator overloading”. So the main idea behind
“Operator overloading” is to use C++ operators with class variables or class objects.
Redefining the meaning of operators really does not change their original meaning;
instead, they have been given additional meaning along with their existing ones.
Example of Operator Overloading in C++
// C++ Program to Demonstrate
// Operator Overloading
#include <iostream>
using namespace std;

class Complex {
private:
int real, imag;

public:
Complex(int r = 0, int i = 0)
{
real = r;
imag = i;
}

// This is automatically called when '+' is used with


// between two Complex objects
Complex operator+(Complex const& obj)
{
Complex res;
res.real = real + obj.real;
res.imag = imag + obj.imag;
return res;
}
void print() { cout << real << " + i" << imag << '\n'; }
};

int main()
{
Complex c1(10, 5), c2(2, 4);
Complex c3 = c1 + c2;
c3.print();
}

Output
12 + i9
Operators that can be Overloaded in C++
We can overload
 Unary operators
 Binary operators
 Special operators ( [ ], (), etc)

But, among them, there are some operators that cannot be overloaded. They
are
 Scope resolution operator (::)(::)
 Member selection operator
 Member selection through *

Pointer to a member variable


 Conditional operator (?:)(?:)
 Sizeof operator sizeof()

Operators that can be overloaded Examples

Binary Arithmetic +, -, *, /, %

Unary Arithmetic +, -, ++, —

Assignment =, +=,*=, /=,-=, %=

Bitwise & , | , << , >> , ~ , ^

De-referencing (->)

Dynamic memory allocation,


New, delete
De-allocation

Subscript []

Function call ()

Logical &, | |, !
Operators that can be overloaded Examples

Relational >, < , = =, <=, >=

Why can’t the above-stated operators be overloaded?


1. sizeof Operator
This returns the size of the object or datatype entered as the operand. This is
evaluated by the compiler and cannot be evaluated during runtime. The
proper incrementing of a pointer in an array of objects relies on the sizeof
operator implicitly. Altering its meaning using overloading would cause a
fundamental part of the language to collapse.

2. typeid Operator
This provides a CPP program with the ability to recover the actually derived
type of the object referred to by a pointer or reference. For this operator, the
whole point is to uniquely identify a type. If we want to make a user-defined
type ‘look’ like another type, polymorphism can be used but the meaning of
the typeid operator must remain unaltered, or else serious issues could
arise.

3. Scope resolution (::) Operator


This helps identify and specify the context to which an identifier refers by
specifying a namespace. It is completely evaluated at runtime and works on
names rather than values. The operands of scope resolution are note
expressions with data types and CPP has no syntax for capturing them if it
were overloaded. So it is syntactically impossible to overload this operator.

4. Class member access operators (.(dot), .* (pointer to member


operator))
The importance and implicit use of class member access operators can be
understood through the following example:

Example:
// C++ program to demonstrate operator overloading
// using dot operator
#include <iostream>
using namespace std;
class ComplexNumber {
private:
int real;
int imaginary;

public:
ComplexNumber(int real, int imaginary)
{
this->real = real;
this->imaginary = imaginary;
}
void print() { cout << real << " + i" << imaginary; }
ComplexNumber operator+(ComplexNumber c2)
{
ComplexNumber c3(0, 0);
c3.real = this->real + c2.real;
c3.imaginary = this->imaginary + c2.imaginary;
return c3;
}
};
int main()
{
ComplexNumber c1(3, 5);
ComplexNumber c2(2, 4);
ComplexNumber c3 = c1 + c2;
c3.print();
return 0;
}

Output
5 + i9

5. Ternary or conditional (?:) Operator


The ternary or conditional operator is a shorthand representation of an if-else
statement. In the operator, the true/false expressions are only evaluated on
the basis of the truth value of the conditional expression.
conditional statement ? expression1 (if statement is TRUE) :
expression2 (else)
A function overloading the ternary operator for a class say ABC using the
definition
ABC operator ?: (bool condition, ABC trueExpr, ABC falseExpr);
would not be able to guarantee that only one of the expressions was
evaluated. Thus, the ternary operator cannot be overloaded.
Types of Operator Overloading in C++

C++ provides a special function to change the current functionality of some operators
within its class which is often called as operator overloading. Operator Overloading is
the method by which we can change some specific operators’ functions to do different
tasks.
Syntax:
Return_Type classname :: operator op(Argument list)
{
Function Body
} // This can be done by declaring the function
Here,
 Return_Type is the value type to be returned to another object.
 operator op is the function where the operator is a keyword.
 op is the operator to be overloaded.

Operator Overloading can be done by using two approaches, i.e.


1. Overloading Unary Operator.
2. Overloading Binary Operator.

Criteria/Rules to Define the Operator Function


1. In the case of a non-static member function, the binary operator should have only
one argument and the unary should not have an argument.
2. In the case of a friend function, the binary operator should have only two
arguments and the unary should have only one argument.
3. Operators that cannot be overloaded are .* :: ?:
4. Operators that cannot be overloaded when declaring that function as friend
function are = () [] ->.
5. The operator function must be either a non-static (member function), global free
function or a friend function.
Refer to this, for more rules of Operator Overloading.
Operator overloading allows you to redefine the way operators work with user-
defined types. To master the various types of operator overloading in C++, explore
the C++ Course, which provides comprehensive tutorials and examples.
1. Overloading Unary Operator
Let us consider overloading (-) unary operator. In the unary operator function, no
arguments should be passed. It works only with one class object. It is the overloading
of an operator operating on a single operand.
Example: Assume that class Distance takes two member objects i.e. feet and inches,
and creates a function by which the Distance object should decrement the value of feet
and inches by 1 (having a single operand of Distance Type).
// C++ program to show unary
// operator overloading
#include <iostream>
using namespace std;

class Distance {
public:
int feet, inch;

// Constructor to initialize
// the object's value
Distance(int f, int i)
{
this->feet = f;
this->inch = i;
}

// Overloading(-) operator to
// perform decrement operation
// of Distance object
void operator-()
{
feet--;
inch--;
cout << "\nFeet & Inches(Decrement): " <<
feet << "'" << inch;
}
};

// Driver Code
int main()
{
Distance d1(8, 9);

// Use (-) unary operator by


// single operand
-d1;
return 0;
}

Output
Feet & Inches(Decrement): 7'8
Explanation: In the above program, it shows that no argument is passed and no
return_type value is returned, because the unary operator works on a single operand.
(-) operator changes the functionality to its member function.
Note: d2 = -d1 will not work, because operator-() does not return any value.

2. Overloading Binary Operator


In the binary operator overloading function, there should be one argument to be
passed. It is the overloading of an operator operating on two operands. Below is the
C++ program to show the overloading of the binary operator (+) using a class
Distance with two distant objects.
// C++ program to show binary
// operator overloading
#include <iostream>
using namespace std;

class Distance {
public:
int feet, inch;

Distance()
{
this->feet = 0;
this->inch = 0;
}

Distance(int f, int i)
{
this->feet = f;
this->inch = i;
}

// Overloading (+) operator to


// perform addition of two distance
// object
// Call by reference
Distance operator+(Distance& d2)
{
// Create an object to return
Distance d3;

d3.feet = this->feet + d2.feet;


d3.inch = this->inch + d2.inch;

// Return the resulting object


return d3;
}
};

// Driver Code
int main()
{
Distance d1(8, 9);
Distance d2(10, 2);
Distance d3;

// Use overloaded operator


d3 = d1 + d2;

cout << "\nTotal Feet & Inches: " <<


d3.feet << "'" << d3.inch;
return 0;
}

Output
Total Feet & Inches: 18'11
Early binding and Late binding in C++

Binding refers to the process of converting identifiers (such as variable and
performance names) into addresses. Binding is done for each variable and
functions. For functions, it means that matching the call with the right
function definition by the compiler. It takes place either at compile time or at
runtime.

Early Binding (compile-time time polymorphism) As the name indicates,


compiler (or linker) directly associate an address to the function call. It
replaces the call with a machine language instruction that tells the mainframe
to leap to the address of the function.
By default early binding happens in C++. Late binding (discussed below) is
achieved with the help of virtual keyword)

// CPP Program to illustrate early binding.

// Any normal function call (without virtual)

// is binded early. Here we have taken base

// and derived class example so that readers


// can easily compare and see difference in

// outputs.

#include<iostream>

using namespace std;

class Base

public:

void show() { cout<<" In Base \n"; }

};

class Derived: public Base

public:

void show() { cout<<"In Derived \n"; }

};

int main(void)

Base *bp = new Derived;

// The function call decided at

// compile time (compiler sees type


// of pointer and calls base class

// function.

bp->show();

return 0;

Output:
In Base
Late Binding : (Run time polymorphism) In this, the compiler adds code
that identifies the kind of object at runtime then matches the call with the
right function definition (Refer this for details). This can be achieved by
declaring a virtual function.

// CPP Program to illustrate late binding

#include<iostream>

using namespace std;

class Base

public:

virtual void show() { cout<<" In Base \n"; }

};
class Derived: public Base

public:

void show() { cout<<"In Derived \n"; }

};

int main(void)

Base *bp = new Derived;

bp->show(); // RUN-TIME POLYMORPHISM

return 0;

Output:
In Derived

You might also like