0% found this document useful (0 votes)
8 views18 pages

lab 10 oop

The document is a lab manual focused on polymorphism in object-oriented programming, specifically in C++. It covers the concepts of virtual functions, dynamic binding, abstract classes, and provides examples through various tasks involving class hierarchies like Animal, Person, and GeometricShape. The manual emphasizes the importance of polymorphism in enhancing code reusability and extensibility.

Uploaded by

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

lab 10 oop

The document is a lab manual focused on polymorphism in object-oriented programming, specifically in C++. It covers the concepts of virtual functions, dynamic binding, abstract classes, and provides examples through various tasks involving class hierarchies like Animal, Person, and GeometricShape. The manual emphasizes the importance of polymorphism in enhancing code reusability and extensibility.

Uploaded by

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

Lab Manual for Object-Oriented Programming

(LAB-10)
Reusability IV
Polymorphism in Object Oriented Programming
Lab 10: Polymorphism in Object Oriented
Programming
1. Introduction
In general, polymorphism means ‘various shapes’ and within the context of an object-oriented
programming (OOP) language, it is the ability of an object to acquire various forms while
referencing various instances of the different classes in inheritance hierarchy. In OOP, a
significant characteristic is the type compatibility of a derived class pointer to its base class
pointer. Taking advantage of this useful aspect, polymorphism establishes a new way of
programming.

To realize polymorphism in C++, you need


 A virtual function and
 A pointer of base class type

A member function of a base class can be made a virtual function if it is probable to redefine
(override) this function in the derived class. The significance of making a function virtual
becomes evident when you want to invoke function of derived class from a pointer of base class
referencing derived class’s object. Following code provides an example of polymorphism
mechanism in C++.

class Base
{
public:
virtual void func()
{
cout<<”Base Class Function”;
}
};

class Derived: public Base


{
public:
void func()
{
cout<<”Derived Class Function”;
}
};
void main()
{
Base *bPtr;
Derived dev;
bPtr = &dev;
bPtr->func();
}
Upon calling func() with bPtr, Derived class func() will be invoked and output would be
“Derived Class Function”. In the absence of virtual keyword, func() of base would be called
each time. Hence, it can be concluded that virtual keyword allow a pointer of base class to call
appropriate function of any of its derived class to whom it is referencing. In this way, each time a
different function will be invoked with the same function call. With polymorphism, compiler
does not know which function to call at compile and thus appropriate function call is deferred to
runtime. At runtime, the type of object that a base class pointer is pointing is recognized to call
proper function. This is known as dynamic or late binding.

Virtual keyword can also be used with destructors and classes. However, virtual keyword
possesses different meanings when used with destructor and classes as explained below.
Virtual Destructors:
In practice, it is always recommended to make the base class destructor as virtual. In the absence
of virtual keyword with base class destructor, upon deletion of any derived class’s object only
destructor of base class would be called.

Virtual Base Classes:


Virtual base classes can be used to avoid diamond problem of multiple inheritance that is
explained as under.

class Base
{
protected:
void func()
{ cout<<”A Base Class Function”; }
};
class Derived1: public Base{ };
class Derived2: public Base{ };
class Derived3: public Derived1, public Derived2
{ };

In the code above, both (Derived1 and Derived2) classes contain a copy of func(), which is
inherited from class Base. Upon the invocation of func() with an object of Derived3 class,
compiler would be unable to decide which copy to use.

To overcome this situation, it is required to use virtual keyword with base class inheritance.
Hence, the above code would be implemented as

class Base
{
protected:
void func()
{ cout<<”A Base Class Function”; }
};
class Derived1: virtual public Base{ };
class Derived2: virtual public Base{ };
class Derived3: public Derived1, public Derived2
{ };

Pure Virtual Function and Abstract Class:


You may have observed that with any class hierarchy in OOP, derived class(es) become more
specific version of base class(es) which are more general or abstract. It is sometime good in
practice to make the base class as abstract class that contains only the most common features of
all of its derived classes. In C++, you can make base class an abstract class by declaring a pure
virtual function in it. The syntax is given as under:

class Base
{
protected:
virtual void func() = 0;
};

Instantiation of an abstract class is not possible and you should override pure virtual function in
derived class(es).

2. Objective of the Experiment


After completing this lab, the student should be able to:
 Distinguish between static binding and dynamic binding
 Understand polymorphism and dynamic binding while using virtual functions
 Declare abstract classes with pure virtual function

3. Concept Map
Following encapsulation and inheritance, polymorphism is the third important capability of OOP
paradigm. The fundamental inspiration behind polymorphism is that of dynamic binding. In this
way, at compile time, compiler knows nothing about which function to call. On the contrary,
decision is made at runtime. Polymorphism helps programmer to make program in general rather
than specific. In simple words, it provides a single interface with different implementations.
Moreover, polymorphism facilitates program extensibility while permitting new derived classes
and functions to be added to an inheritance hierarchy without modifying application programs
that already utilize various interfaces of that inheritance hierarchy. However, for beginners, it is
difficult to grasp and implement the concept of polymorphism, dynamic binding, and abstract
classes.
LAB TASK

Task 1:
Consider an abstract class Animal having
 A datamember “Name”
 A datamember “Zoo”
 A single function named show()

A class named Birds inherits Animal class and adds fields representing
 A bool type variable flying
 Override function named show() to display values of its all attributes

A class named Reptiles inherits BOOK class and adds fields representing
 Length
 Override function named show() to display values of its all attributes

#include <iostream>
#include <string>
using namespace std;

// Abstract base class


class Animal {
protected:
string Name;
string Zoo;

public:
Animal(string n, string z) : Name(n), Zoo(z) {}

// Pure virtual function


virtual void show() = 0;

// Virtual destructor for proper cleanup


virtual ~Animal() {}
};

// Derived class: Birds


class Birds : public Animal {
private:
int flying; // Using int instead of bool, as per your preferences
public:
Birds(string n, string z, int f) : Animal(n, z), flying(f) {}

void show() override {


cout << "Bird Name: " << Name << endl;
cout << "Zoo: " << Zoo << endl;
cout << "Can Fly: " << (flying ? "Yes" : "No") << endl;
}
};

// Derived class: Reptiles


class Reptiles : public Animal {
private:
float Length;

public:
Reptiles(string n, string z, float l) : Animal(n, z), Length(l) {}

void show() override {


cout << "Reptile Name: " << Name << endl;
cout << "Zoo: " << Zoo << endl;
cout << "Length: " << Length << " meters" << endl;
}
};

// Example usage
int main() {
Birds b("Parrot", "Lahore Zoo", 1);
Reptiles r("Crocodile", "Karachi Zoo", 5.2f);

Animal* a1 = &b;
Animal* a2 = &r;

a1->show();
cout << endl;
a2->show();

return 0;
}
Task 2
Create a class named Person, which contains
 A pure virtual function named print()
 Two data fields i.e. personName and age
A class named Student inherits Person class, which contains
 Two data fields i.e. Std_id and Cgpa
 Overridden function print() to display all details relevant to a patient

A class named Regular inherited from class Student which holds


 A data field representing the name of School
 A data filed representing the Fee
 Overridden function print() to display all details relevant to a Regular student

#include <iostream>
#include <string>
using namespace std;

// Abstract Base Class


class Person {
protected:
string personName;
int age;

public:
Person(string name, int a) : personName(name), age(a) {}

virtual void print() = 0; // Pure virtual function

virtual ~Person() {}
};

// Derived Class: Student


class Student : public Person {
protected:
int Std_id;
float Cgpa;

public:
Student(string name, int a, int id, float c)
: Person(name, a), Std_id(id), Cgpa(c) {}

void print() override {


cout << "Student Name: " << personName << endl;
cout << "Age: " << age << endl;
cout << "Student ID: " << Std_id << endl;
cout << "CGPA: " << Cgpa << endl;
}
};

// Derived Class: Regular Student


class Regular : public Student {
private:
string SchoolName;
float Fee;

public:
Regular(string name, int a, int id, float c, string school, float fee)
: Student(name, a, id, c), SchoolName(school), Fee(fee) {}

void print() override {


cout << "Regular Student Name: " << personName << endl;
cout << "Age: " << age << endl;
cout << "Student ID: " << Std_id << endl;
cout << "CGPA: " << Cgpa << endl;
cout << "School Name: " << SchoolName << endl;
cout << "Fee: " << Fee << endl;
}
};

// Example usage
int main() {
Regular r("Ali", 27,535004 , 3.92, "NUST", 250000);

Person* p = &r;
p->print();

return 0;
}

Task 3

Create a class named GeometricShape containing


 A pure virtual function named show() is create in the GeometricShape class

Derive a class named Rectangle from class GeometricShape that includes


 data members for the length and width of a rectangle,
 respective mutator and accessor functions to set and get values of length and width, and
 overriding function named computeArea() to compute the area of rectangle (length x
width)
 overriding function named show() to display the details associated with an instance of
class Rectangle
In the main function, create instances of derived classes to access respective show() function
using dynamic binding.

#include <iostream>
using namespace std;

// Abstract base class


class GeometricShape {
public:
virtual void show() = 0; // Pure virtual function
virtual ~GeometricShape() {}
};

// Derived class: Rectangle


class Rectangle : public GeometricShape {
private:
float length;
float width;

public:
// Constructor
Rectangle() : length(0), width(0) {}

// Mutators
void setLength(float l) {
length = l;
}

void setWidth(float w) {
width = w;
}

// Accessors
float getLength() {
return length;
}

float getWidth() {
return width;
}

// Function to compute area


float computeArea() {
return length * width;
}
// Overriding show()
void show() override {
cout << "Rectangle Details:" << endl;
cout << "Length: " << length << endl;
cout << "Width: " << width << endl;
cout << "Area: " << computeArea() << endl;
}
};

// Main function
int main() {
// Create object dynamically
GeometricShape* shape = new Rectangle();

// Downcast to Rectangle to access mutators


Rectangle* rect = dynamic_cast<Rectangle*>(shape);
if (rect) {
rect->setLength(10);
rect->setWidth(5);
}

// Dynamic binding to call show()


shape->show();

// Clean up
delete shape;

return 0;
}
Task 4

Testing
 For Task 1, it is required to check the assignment of derived class instances to base class
pointer. Moreover, (while considering the dynamic binding) test the invocation of
respective show() function.

 For Task 2, it is required to check the assignment of derived class instances to base class
pointer. Moreover, (while considering the dynamic binding) test the invocation of
respective print() function.

#include <iostream>
#include <string>
using namespace std;

//////////////////////////////////////////////////
// Task 1: Animal → Birds, Reptiles
//////////////////////////////////////////////////
// Abstract base class
class Animal {
protected:
string Name;
string Zoo;

public:
Animal(string name, string zoo) : Name(name), Zoo(zoo) {}

virtual void show() = 0; // Pure virtual function


virtual ~Animal() {}
};

// Derived class: Birds


class Birds : public Animal {
private:
bool flying;

public:
Birds(string name, string zoo, bool isFlying)
: Animal(name, zoo), flying(isFlying) {}

void show() override {


cout << "\n[Task 1] Bird Details:\n";
cout << "Name: " << Name << endl;
cout << "Zoo: " << Zoo << endl;
cout << "Flying: " << (flying ? "Yes" : "No") << endl;
}
};

// Derived class: Reptiles


class Reptiles : public Animal {
private:
float Length;

public:
Reptiles(string name, string zoo, float len)
: Animal(name, zoo), Length(len) {}

void show() override {


cout << "\n[Task 1] Reptile Details:\n";
cout << "Name: " << Name << endl;
cout << "Zoo: " << Zoo << endl;
cout << "Length: " << Length << " meters" << endl;
}
};

//////////////////////////////////////////////////
// Task 2: Person → Student → Regular
//////////////////////////////////////////////////

// Abstract base class


class Person {
protected:
string personName;
int age;

public:
Person(string name, int a) : personName(name), age(a) {}

virtual void print() = 0; // Pure virtual function


virtual ~Person() {}
};

// Derived class: Student


class Student : public Person {
protected:
int Std_id;
float Cgpa;

public:
Student(string name, int a, int id, float c)
: Person(name, a), Std_id(id), Cgpa(c) {}

void print() override {


cout << "\n[Task 2] Student Details:\n";
cout << "Name: " << personName << endl;
cout << "Age: " << age << endl;
cout << "Student ID: " << Std_id << endl;
cout << "CGPA: " << Cgpa << endl;
}
};
// Derived class: Regular
class Regular : public Student {
private:
string SchoolName;
float Fee;

public:
Regular(string name, int a, int id, float c, string school, float fee)
: Student(name, a, id, c), SchoolName(school), Fee(fee) {}

void print() override {


cout << "\n[Task 2] Regular Student Details:\n";
cout << "Name: " << personName << endl;
cout << "Age: " << age << endl;
cout << "Student ID: " << Std_id << endl;
cout << "CGPA: " << Cgpa << endl;
cout << "School: " << SchoolName << endl;
cout << "Fee: " << Fee << endl;
}
};

//////////////////////////////////////////////////
// Main Function: Demonstration of Dynamic Binding
//////////////////////////////////////////////////

int main() {
// ----- Task 1 -----
Animal* a1 = new Birds("Parrot", "Safari Zoo", true);
Animal* a2 = new Reptiles("Python", "City Zoo", 3.5);

a1->show(); // dynamic binding to Birds::show()


a2->show(); // dynamic binding to Reptiles::show()

delete a1;
delete a2;

// ----- Task 2 -----


Person* p = new Regular("Ali", 22, 535004, 3.92, "NUST", 250000);

p->print(); // dynamic binding to Regular::print()

delete p;

return 0;
}

You might also like