0% found this document useful (0 votes)
22 views23 pages

Oop Unit 3 by Imp Notes Se Comp Sppu

The document provides an overview of polymorphism in C++, including its definition, types (compile-time and run-time), and real-life examples. It explains concepts such as virtual functions, pure virtual functions, abstract classes, and operator overloading, along with their syntax and rules. Additionally, it discusses the importance of virtual destructors, singleton classes, and the distinction between container and contained classes.

Uploaded by

j2dtzwc2k2
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
22 views23 pages

Oop Unit 3 by Imp Notes Se Comp Sppu

The document provides an overview of polymorphism in C++, including its definition, types (compile-time and run-time), and real-life examples. It explains concepts such as virtual functions, pure virtual functions, abstract classes, and operator overloading, along with their syntax and rules. Additionally, it discusses the importance of virtual destructors, singleton classes, and the distinction between container and contained classes.

Uploaded by

j2dtzwc2k2
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 23

Unit III

Polymorphism

Introduction to polymorphism:
o The term "Polymorphism" is the combination of "poly" + "morphs" which means many
forms.
o It is a greek word. In object-oriented programming, we use 3 main concepts: inheritance,
encapsulation, and polymorphism.

Real Life Example Of Polymorphism:

A lady behaves like a teacher in a classroom, mother or daughter in a home and customer
in a market. Here, a single person is behaving differently according to the situations.

There are two types of polymorphism in C++:

o Compile time polymorphism: The overloaded functions are invoked by matching the
type and number of arguments. This information is available at the compile time and,
therefore, compiler selects the appropriate function at the compile time. It is achieved by
function overloading and operator overloading which is also known as static binding or
early binding. Now, let's consider the case where function name and prototype is same.

class A // base class


declaration.
{
int a;
public:
void display()
{
cout<< "Class A ";
}
};
class B : public A // derived class
declaration.
{
int b;
public:
void display()
{
cout<<"Class B";
}
};
o In the above case, the prototype of display() function is the same in both the base and
derived class. Therefore, the static binding cannot be applied. It would be great if the
appropriate function is selected at the run time. This is known as run time polymorphism.
o Run time polymorphism: Run time polymorphism is achieved when the object's method
is invoked at the run time instead of compile time. It is achieved by method overriding
which is also known as dynamic binding or late binding.Differences b/w compile time
and run time polymorphism.

Pointers to objects:

o You can access an object either directly, or by using a pointer to the object.
o To access an element of an object when using the actual object itself, use the dot
operator.
o To access a specific element of an object when using a pointer to the object, you must use
the arrow operator.
o To declare an object pointer, you use the same declaration syntax that you would use for
any other pointer type.
Example:
#include <iostream>
using namespace std;

class My_Class {/* w w w . de m o 2 s. c o m*/


int num;
public:
void set_num(int val) {num = val;}
void show_num();
};

void My_Class::show_num()
{
cout << num << "\n";
}

int main()
{
My_Class ob, *p; // declare an object and pointer to it

ob.set_num(1); // access ob directly


ob.show_num();

p = &ob; // assign p the address of ob


p->show_num(); // access ob using pointer

return 0;
}
virtual function:

o A C++ virtual function is a member function in the base class that you redefine in a
derived class. It is declared using the virtual keyword.
o It is used to tell the compiler to perform dynamic linkage or late binding on the function.
o There is a necessity to use the single pointer to refer to all the objects of the different
classes. So, we create the pointer to the base class that refers to all the derived objects.
But, when base class pointer contains the address of the derived class object, always
executes the base class function. This issue can only be resolved by using the 'virtual'
function.
o A 'virtual' is a keyword preceding the normal declaration of a function.
o When the function is made virtual, C++ determines which function is to be invoked at the
runtime based on the type of the object pointed by the base class pointer.

Rules of Virtual Function:

o Virtual functions must be members of some class.


o Virtual functions cannot be static members.
o They are accessed through object pointers.
o They can be a friend of another class.
o A virtual function must be defined in the base class, even though it is not used.
o The prototypes of a virtual function of the base class and all the derived classes must be
identical. If the two functions with the same name but different prototypes, C++ will
consider them as the overloaded functions.
o We cannot have a virtual constructor, but we can have a virtual destructor
o Consider the situation when we don't use the virtual keyword.

virtual function Example:

#include <iostream>
{
public:
virtual void display()
{
cout << "Base class is invoked"<<endl;
}
};
class B:public A
{
public:
void display()
{
cout << "Derived Class is invoked"<<endl;
}
};
int main()
{
A* a; //pointer of base class
B b; //object of derived class
a = &b;
a->display(); //Late Binding occurs
}
Output:

Derived Class is invoked

Pure Virtual Function:

o A virtual function is not used for performing any task. It only serves as a placeholder.
o When the function has no definition, such function is known as "do-nothing" function.
o The "do-nothing" function is known as a pure virtual function. A pure virtual function
is a function declared in the base class that has no definition relative to the base class.
o A class containing the pure virtual function cannot be used to declare the objects of its
own, such classes are known as abstract base classes.
o The main objective of the base class is to provide the traits to the derived classes and to
create the base pointer used for achieving the runtime polymorphism.

Pure virtual function can be defined as:

virtual void display() = 0;

example:

#include <iostream>
using namespace std;
class Base
{
public:
virtual void show() = 0;
};
class Derived : public Base
{
public:
void show()
{
std::cout << "Derived class is derived from the base
class." << std::endl;
}
};
int main()
{
Base *bptr;
//Base b;
Derived d;
bptr = &d;
bptr->show();
return 0;
}
Output:

Derived class is derived from the base class.

Abstract base class:

o An abstract class is a class that is designed to be specifically used as a base class.


o An abstract class contains at least one pure virtual function.
o You declare a pure virtual function by using a pure specifier (= 0) in the declaration of a
virtual member function in the class declaration.

The following is an example of an abstract class:

class AB {
public:
virtual void f() = 0;
};
Example:
#include <iostream>
using namespace std;
class Base_abstract
{
public:
virtual void print() = 0; //Pure Virtual Function
};
class Derived_class : public Base_abstract
{
public:
void print()
{
std::cout << "Overriding pure virtual function in
derived class \n " << std::endl;
}
};
int main()
{
Base_abstract *b;
Derived_class d;
b = &d;
b->print();
return 0;
}
Output:

Overriding pure virtual function in derived class


Difference between virtual and pure virtual function:

polymorphic classes
o The typical example is an abstract shape class, that can then be derived into squares,
circles, and other concrete shapes.

The parent class:

Let's start with the polymorphic class:

class Shape {

public:

virtual ~Shape() = default;

virtual double get_surface() const = 0;

virtual void describe_object() const { std::cout << "this is


a shape" << std::endl; }

double get_doubled_surface() const { return 2 *


get_surface(); }

};

A polymorphic class should always define a virtual destructor.

A class that contains at least one pure virtual function is an abstract class. Abstract classes cannot
be instantiated. You may only have pointers or references of an abstract class type.

Destructor :

o A destructor in C++ is a member function of a class used to free the space occupied by
or delete an object of the class that goes out of scope.
o A destructor has the same name as the name of the constructor function in a class, but the
destructor uses a tilde (~) sign before its function name.

Virtual Destructor:

o A virtual destructor is used to free up the memory space allocated by the derived class
object or instance while deleting instances of the derived class using a base class pointer
object.
o A base or parent class destructor use the virtual keyword that ensures both base class and
the derived class destructor will be called at run time, but it called the derived class first
and then base class to release the space occupied by both destructors.

Write a program to display a class destructor's behavior using a virtual destructor in C ++.

#include<iostream>
using namespace std;
class Base
{
public:
Base() // Constructor member function.
{
cout << "\n Constructor Base class"; // It prints first.
}
virtual ~Base() // Define the virtual destructor function to
call the Destructor Derived function.
{
cout << "\n Destructor Base class"; /
}
};
// Inheritance concept
class Derived: public Base
{
public:
Derived() // Constructor function.
{
cout << "\n Constructor Derived class" ; /* After print the
Constructor Base, now it will prints. */
}
~Derived() // Destructor function
{
cout << "\n Destructor Derived class"; /* The virtual Base
Class? Destructor calls it before calling the Base Class
Destructor. */
}
};
int main()
{
Base *bptr = new Derived; // A pointer object reference the
Base class.
delete bptr; // Delete the pointer object.
}
Output:

Early Binding:

o This is compile time polymorphism.


o Here it directly associates an address to the function call. For function overloading it is an
example of early binding.

Example:

#include<iostream>
using namespace std;
class Base {
public:
void display() {
cout<<" In Base class" <<endl;
}
};
class Derived: public Base {
public:
void display() {
cout<<"In Derived class" << endl;
}
};
int main(void) {
Base *base_pointer = new Derived;
base_pointer->display();
return 0;
}
Output

In Base class
Late Binding:

o This is run time polymorphism.


o In this type of binding the compiler adds code that identifies the object type at runtime
then matches the call with the right function definition.
o This is achieved by using virtual function.

Example

#include<iostream>
using namespace std;
class Base {
public:
virtual void display() {
cout<<"In Base class" << endl;
}
};
class Derived: public Base {
public:
void display() {
cout<<"In Derived class" <<endl;
}
};
int main() {
Base *base_pointer = new Derived;
base_pointer->display();
return 0;
}

Output

In Derived class

Container classes and Contained classes:

o A container class is a class that is used to hold objects in memory or external storage.
o A container class acts as a generic holder.
o A container class has a predefined behavior and a well-known interface.
o A nested class or a contained class is a class that is declared in another class.
o The nested class is also a member variable of the enclosing and has the same access right
as the other member.

Example:
#include<iostream>
Using namespace std;
Class A
{
Public:
Class B
{
private:
int num;
Public:
void getdata(int n)
{
num=n;
}
void putdata()
{
cout <<”The number is “<<num;
}
};
};
int main()
{
cout <<”Nested Classes in C++ “<<endl;
A::B obj;
obj. getdata(9);
obj. putdata();
return 0;
}
Output:

Nested Classes in C++

The number is 9

Containership :
o This type of relationship between classes is known as containership or has_a relationship
as one class contain the object of another class.
o And the class which contains the object and members of another class in this kind of
relationship is called a container class.

Singleton class:
o Singleton design pattern is a software design principle that is used to restrict the
instantiation of a class to one object.
o This is useful when exactly one object is needed to coordinate actions across the system.
o For example, if you are using a logger, that writes logs to a file, you can use a singleton
class to create such a logger. You can create a singleton class using the following code −

Example

#include <iostream>
using namespace std;
class Singleton {
static Singleton *instance;
int data;

// Private constructor so that no objects can be created.


Singleton() {
data = 0;
}

public:
static Singleton *getInstance() {
if (!instance)
instance = new Singleton;
return instance;
}

int getData() {
return this -> data;
}

void setData(int data) {


this -> data = data;
}
};

//Initialize pointer to zero so that it can be initialized in


first call to getInstance
Singleton *Singleton::instance = 0;

int main(){
Singleton *s = s->getInstance();
cout << s->getData() << endl;
s->setData(1000);
cout << s->getData() << endl;
return 0;
}
Output:

This will give the output −


0
1000

Fundamentals of operator overloading:


o operator overloading is one of the many existing feature of c++. The existing operator
can be given new definitions and used with user defined data type .
o Most of operator existing in C/C++ can work with numerical data to produce some result.
E.g. the +operator can be used for addition of two numbers.
o A special function to change the current functionality of some operators within its class
which is often called as operator overloading.
o Operator Overloading is the method by which we can change the function of some
specific operators to do some different task.
Operator Overloading can be done by using three approaches, they are

1. Overloading unary operator.


2. Overloading binary operator.
3. Overloading binary operator using a friend function.

syntax

Return_Type Operator +(Argument list)


{
Statements
}
o In the above syntax Return_Type is value type to be returned to another object, operator
op is the function where the operator is a keyword and op is the operator to be
overloaded.
o Operator function must be either non-static (member function) or friend function.

Restrictions on Operators Overloading

Following are some restrictions to be kept in mind while implementing operator overloading.

o In case of a non-static function, the binary operator should have only one argument and
unary should not have an argument.
o In the case of a friend function, the binary operator should have only two argument and
unary should have only one argument.
o All the class member object should be public if operator overloading is implemented.
o Operators that cannot be overloaded are.
size of Size of operator
. Member access operator
:: Scope resolution operator
?: Conditional operator
.* Pointer to member operator

o Operator cannot be used to overload when declaring that function as friend


function = () [] ->.
o Precedence and Associativity of an operator cannot be changed.
o Any (numbers of Operands) cannot be changed.
o Unary operator remains unary, binary remains binary etc.
o No new operators can be created, only existing operators can be overloaded.
o Cannot redefine the meaning of a procedure. You cannot change how integers are added.

Operator Functions as Class Members vs. as Friend Functions

o We can learned how to overload the arithmetic operator using friend function .
o We also learned we can overload operators as normal function.
o Many operators can be overloaded in a different way: as a member function.
o Overloading operators using a member function is very similar to overloading
operator using a friend function. When overloading an operator using a member
function:
o To overloaded operator must be added as a member function of the left operand
o Left operand become the implicit *this object.
o All other operand become function parameters.

Operator Overloading as Friend Function:

#include <iostream>

using namespace std;

class Cents
{
private:

int m_cents;

public:

Cents(int cents)
{
m_cents= cents;
}

// Overload Cents + int

friend Cents operator+(const Cents &cents,int value);

int getCents() const


{
return m_cents;
}
};

//note:this function is not a member function!

Cents operator+(const Cents &cents,int value)


{
return Cents(cents.m_cents + value);
}

int main()
{
Cents cents1(16);

Cents cents2=cents1+2;

cout<<”I have”<<cents2.getCents()<<” cents.\n”;


return 0;
}

Operator Overloading as Member Function:

#include <iostream>

using namespace std;

class Cents
{
private:

int m_cents;

public:

Cents(int cents)
{
m_cents= cents;
}

// Overload Cents + int

Cents operator+( int value);

int getCents() const


{
return m_cents;
}
};

//note:this function is not a member function!

//the cents parameter in the friend version is now the


implicit *this parameter

Cents Cents::operator+( int value)


{
return Cents(m_cents + value);
}

int main()
{
Cents cents1(16);
Cents cents2=cents1+2;

cout<<”I have”<<cents2.getCents()<<” cents.\n”;


return 0;
}

Overloading Unary Operators:

o Overloading Unary Operator: Let us consider to overload (-) unary operator.


o In unary operator function, no arguments should be passed.
o It works only with one class objects. It is a overloading of an operator operating
on a single operand.

Example:

Assume that class Distance takes two member object i.e. feet and inches, create a
function by which Distance object should decrement the value of feet and inches by 1
(having single operand of Distance Type).

#include <iostream>

using namespace std;

class Distance {
public:

// Member Object
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()
{
// Declare and Initialize the constructor
Distance d1(8, 9);

// Use (-) unary operator by single operand


-d1;
return 0;
}

Output:

Feet & Inches(Decrement): 7'8

In the above program, it shows that no argument is passed and no return_type value is
returned, because unary operator works on a single operand. (-) operator change the
functionality to its member function.

Note: d2 = -d1 will not work, because operator-() does not return any value.

Overloading Binary Operator:

o In binary operator overloading function, there should be one argument to be


passed.
o It is overloading of an operator operating on two operands.

Example:example of class Distance, but this time, add two distance objects.

#include <iostream>
using namespace std;

class Distance {
public:
// Member Object
int feet, inch;
// No Parameter Constructor
Distance()
{
this->feet = 0;
this->inch = 0;
}

// Constructor to initialize the object's value


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

// Overloading (+) operator to perform addition of


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

// Perform addition of feet and inches


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

// Return the resulting object


return d3;
}
};

// Driver Code
int main()
{
// Declaring and Initializing first object
Distance d1(8, 9);

// Declaring and Initializing second object


Distance d2(10, 2);
// Declaring third object
Distance d3;

// Use overloaded operator


d3 = d1 + d2;

// Display the result


cout << "\nTotal Feet & Inches: " << d3.feet << "'" <<
d3.inch;
return 0;
}

1.

Output:

Total Feet & Inches: 18'11

Distance operator+(Distance &d2), here return type of function is distance and it uses
call by references to pass an argument.

d3 = d1 + d2; here, d1 calls the operator function of its class object and takes d2 as a
parameter, by which operator function return object and the result will reflect in the d3
object.

Overloading Binary Operator using a Friend function:

o In this approach, the operator overloading function must precede with friend
keyword, and declare a function class scope.
o Keeping in mind, friend operator function takes two parameters in a binary
operator, varies one parameter in a unary operator.
o All the working and implementation would same as binary operator function
except this function will be implemented outside of the class scope.

Example:
#include <iostream>

using namespace std;

class Distance {
public:
// Member Object
int feet, inch;

// No Parameter Constructor
Distance()
{
this->feet = 0;
this->inch = 0;
}

// Constructor to initialize the object's value


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

// Declaring friend function using friend keyword


friend Distance operator+(Distance&, Distance&);
};

// Implementing friend function with two parameters


Distance operator+(Distance& d1, Distance& d2) // Call by
reference
{
// Create an object to return
Distance d3;

// Perform addition of feet and inches


d3.feet = d1.feet + d2.feet;
d3.inch = d1.inch + d2.inch;

// Return the resulting object


return d3;
}

// Driver Code
int main()
{
// Declaring and Initializing first object
Distance d1(8, 9);

// Declaring and Initializing second object


Distance d2(10, 2);
// Declaring third object
Distance d3;

// Use overloaded operator


d3 = d1 + d2;

// Display the result


cout << "\nTotal Feet & Inches: " << d3.feet << "'" <<
d3.inch;
return 0;
}

1.

Output:

Total Feet & Inches: 18'11

o Here in the above program, operator function is implemented outside of class


scope by declaring that function as the friend function.
o In these ways, an operator can be overloaded to perform certain tasks by changing
the functionality of operators.

You might also like