0% found this document useful (0 votes)
4 views

Lab Manual 02 - OOP Concepts Review - 2

The document provides a comprehensive overview of Object-Oriented Programming (OOP) concepts, focusing on inheritance, generalization, sub-typing, and access specifiers. It explains the relationships between classes, such as 'is-a' and 'has-a', and details different types of inheritance including single, multilevel, and hierarchical. Additionally, it discusses association, aggregation, and composition, along with the implications of access specifiers in C++ inheritance.

Uploaded by

s2024266134
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)
4 views

Lab Manual 02 - OOP Concepts Review - 2

The document provides a comprehensive overview of Object-Oriented Programming (OOP) concepts, focusing on inheritance, generalization, sub-typing, and access specifiers. It explains the relationships between classes, such as 'is-a' and 'has-a', and details different types of inheritance including single, multilevel, and hierarchical. Additionally, it discusses association, aggregation, and composition, along with the implications of access specifiers in C++ inheritance.

Uploaded by

s2024266134
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/ 27

University of Management and Technology,

Lahore Campus
Lab- 02 Manual
Lab Instructor: Riaz Ahmad
Department of Computer Science
Email: [email protected]

Lab 02: OOP Concepts Review


Inheritance
Inheritance is one of the most important building blocks of OOP. The concept of reusable classes is
helpful to manage objects. You can create new classes (derived classes) that are able to inherit certain
attributes and behavior of their ancestor or base class(es). Prior to working with inheritance, it is
important to consider the following aspects of inheritance.

 Inheritance represents “is-a” relationship in OOP i.e. any specific object is a type of a
more general class of object. For example, Train is a type of Vehicle
 By design, a derived class should inherit all attributes and behaviors of its base class(es)
 While declaring its own data fields a derived class can extend the features of its base
class(es)
 While defining new functionality, a derived class can modify the behavior provided by
the base class(es)

Inheritance in OOP saves a lot of work and time. You can save additional work as some of the object
definitions(class) already exists. Time saving is due to the reason that much of the code has already been
written and tested.
Examples:

Inheritance – “IS A” or “IS A KIND OF” Relationship


Generalization
In OO models, some classes may have common characteristics. We extract these features into a new class
and inherit original classes from this new class. There are many objects with common characteristics in
object model. The common characteristics (attributes and behavior) of all these objects are combined in a
single general class. Base class encapsulates the idea of commonality of derived classes. Base class is
general class representing common behavior of all derived classes.
This concept is known as Generalization.
It reduces the redundancy and gives us reusability, using generalization our solution becomes less complex.
In generalization there should be “Is a Kind of Relationship” (also called “Is A relationship”) between base
and child classes.

Examples: Line, Circle, Triangle


Example: Student, Doctor and Teacher

Common attributes, Common behaviour


Name, age, gender Eat, Walk

Sub-typing & Specialization


We want to add a new class to an existing model. We have developed an existing class hierarchy Find an existing class that
already implements some of the desired state and behavior Inherit the new class from this class and add unique behavior to
the new Class.
Sub-typing (Extension)
Sub-typing means that derived class is behaviorally compatible with the base class Derived class has all the
characteristics of base class plus some extra characteristics Behaviorally compatible means that base class can be
replaced by the derived class.
Sub-typing (Extension) – Example
1. Circle is extending the behavior of shape; it is extending attributes of shape by adding
radius similarly it is extending behavior of shape by adding compute Circumference
and compute Area.
2. Student has two extra attributes program and studyYear Similarly it has extended
behavior by adding study and takeExam.

Note: Every object of derived class has an anonymous object of base class
Default constructor:
Default constructor is such constructor which either has no parameter or if it has some parameters these
have default values. The benefit of default constructor is that it can be used to create class object without
passing any argument.

Implicit Default constructor:


Compiler generates implicit default constructor for any class in case we have not given any constructor for
the class.

Explicit Default constructor:


If user has given constructor for any class without any arguments or with all arguments with default
values then it is also default constructor according to definition but it is explicit (user defined) default
constructor.
Now if a base class has only non-default constructor (constructor with parameters without default values),
then when we will create object of any class derived from this base class compiler will not be able to call
base class constructor as base class has no default constructor (constructor that can be called without
giving any parameters) so compiler will generate error.

We can avoid this error by calling base class non-default constructor in derived class
constructor initializer list by ourself.
Different Types of Inheritance
Example: Implementation of Single level Inheritance [CLO 2]
#include<iostream> class B:public A
using namespace std; {
int b;
class A public:
{ B(int j,int i):A(i)
int a; {
public: b=j;
A(int i) }
{ void show()
a=i; {
} cout<<"\nThe Value of b:"<<b;
void Display() }
{ };
cout<<"\nThe value of a:"<<a;
}
};

int main()
{
B b(4,5);
cout<<" B class";
b.Display();
b.show();

return 0;
}
Example: Implementation of Multilevel Inheritance [CLO 2]
#include<iostream class B:public A class
> using namespace { C:public B{
std; int b; int c;
publi public:
class A c: C()
{ B() {c
int a; { =0;
b=0; }
public:
A() } void setc(int
{ void setb(int i){ c=i;
a=0; i){ b=i; }
} } int
void seta(int int get_c()const{
i){ a=i; getb()const{ r return c;
} eturn b; }
int } void print(){
geta()const{ r void show() this-
eturn a; { >show();
} Display(); cout<<"\n The Value of
void Display() cout<<"\nThe Value of c:"<<get_c();
{ b:"<<getb();
}
cout<<"\nThe value of }
};
a:"<<geta(); };
}
};
int main()
{
C c;
c.seta(4)
;
c.setb(3);
c.setc(2);
c.print();

return 0;
}
Example: Implementation of Hierarchal Inheritance [CLO 2]

#include<iostream> class B:public A class C:public A


using namespace std; { {
int b; int c,d;
class A
{ public: public:
int a; B(int j,int i):A(i) C(int j,int k,int i):A(i)
public: { {
A(int i) b=j; c=j;
{ } d=k;
a=i; void show() }
} { void show()
void Display() cout<<"\nThe Value of {
b:"<<b;
{ cout<<"\nThe Value of
c:"<<c;
} cout<<"\nThe Value of
d:"<<d;
cout<<"\nThe value of a:"<<a; };
} }
}; };
int main()
{
B b(4,5);
C c(8,7,9);

cout<<"\nThe B
class"; b.Display();
b.show();

cout<<" \n\n C
class"; c.Display();
c.show()
; return
0;
}

Association and Aggregation/Composition represent uses-a and has-a relationship,


respectively between objects. It is based on the object-oriented design where an object can
contain other object(s). Association specifies that objects of different kinds are connected
with each other and there exist no ownership and lifecycle dependency. In advance,
aggregation and composition are two types of association representing weak and strong
(whole-part) relationship between contained (whole) and owing (part) objects. Therefore,
aggregation and composition are other forms of code reusability along with inheritance.
Aggregation is a special kind of association represents ownership relationship between
objects. Composition is special kind of aggregation which represents ownership between
objects along with the existence of life-cycle dependency. A department-employees
relationship is an example of aggregation whereas university-departments relationship is an
example of composition.

Association
Interaction of different objects in OO model (or in problem domain) is known as association. In object-
oriented model, objects interact with each other in order to perform some useful work, while modeling
these objects (entities) is done using the association. Usually, an object provides services to several other
objects. An object keeps association with other objects to delegate tasks. This association can be
represented with a line along an arrow head ( ) or without arrow head.
Kinds of Association:
There are two main types of association which are then further subdivided i.e
1. Class Association
2. Object Association
1. Class Association
Class association is implemented in terms of Inheritance. Inheritance implements
generalization/specialization relationship between objects. Inheritance is considered class association.
• In case of public inheritance it is “IS-A” relationship.
• In case of private inheritance, it is “Implemented in terms of” relationship.
This relationship ensures that public members of base class are available to derived class in case of public
inheritance.
When we create objects of classes in which we have implemented inheritance relationships we are forcing
the inheritance relationship between created objects. In this case the derived class objects will also contain
base class objects attributes and methods.

2. Object Association
It is the interaction of stand-alone objects of one class with other objects of anther class.
It can be of one of the following types,
• Simple Association
• Composition
• Aggregation

1.1 Simple Association


The two interacting objects have no intrinsic relationship with other object. It is the weakest link between
objects. It is a reference by which one object can interact with some other object.
 Customer gets cash from cashier
 Employee works for a company
 Ali lives in a house
 Ali drives a car
It is generally called as “association” instead of “simple association”
Kinds of Simple Association

Simple association can be categorized in two ways,


• With respect to direction (navigation)
• With respect to number of objects (cardinality)

Kinds of Simple Association w.r.t Navigation


With respect to navigation association has the following types,
a. One-way Association
b. Two-way Association
a. One-way Association
In One way association we can navigate along a single direction only, it is denoted by an
arrow towards the server object.
Examples:
b.Two-way Association
In two-way association we can navigate in both directions, it is denoted by a line between the
associated objects
Examples:

 Employee works for company

 Company employs employees

Two-way Association - Example

 Yasir is a
friend of Ali
 Ali is a friend
of Yasir

Kinds of Simple Association w.r.t Cardinality


With respect to cardinality association has the following types,
a. Binary Association
b. Ternary Association
c. N-ary Association

a. Binary Association
It associates objects of exactly two classes; it is denoted by a line, or an arrow between the
associated objects.
Example:

Association “works-for” associates objects of exactly two classes

Association “drives” associates’ objects of exactly two classes


b. Ternary Association
It associates objects of exactly three classes; it is denoted by a diamond with lines connected to
associated objects.
Example
Objects of exactly three classes are associated

c. N-ary Association
An association between 3 or more classes its practical examples are very rare.

Composition
An object may be composed of other smaller objects, the relationship between the “part” objects
and the “whole” object is known as Composition, and Composition is represented by a line with
a filled-diamond head towards the composer object
Example – Composition of Ali
Example – Composition of Chair

Composition is stronger relationship:


Composition is a stronger relationship, because
Composed object becomes a part of the composer
Composed object can’t exist independently

Example I
Ali is made up of different body parts
They can’t exist independent of Ali
Example II
Chair’s body is made up of different parts

They can’t exist independently


Code –Example: University has department
#include <iostream>

using namespace std; class


Department{ private:
string DeptName;
public:
Department(string name=""){

this->DeptName=name;
}
void show(){
cout<<"\n Department Name:"<<DeptName;

}
};
class University{
private:
string UName;
Department Dept;
public:
University(string name=""):UName{name}
{
}
void setDept(Department d){ Dept=d;
}
void display(){
cout<<"The University\t "<<UName<<"\t has Department \n";
Dept.show();
}

};
int main()
{
University U("UMT");
Department dpt("CS");
U.setDept(dpt);
U.display();
return 0;
}
Aggregation
An object may contain a collection (aggregate) of other objects, the relationship between the
container and the contained object is called aggregation, Aggregation is represented by a line
with unfilled-diamond head towards the container
Example – Aggregation
Example – Aggregation

Aggregation is weaker relationship


Aggregation is weaker relationship, because
• Aggregate object is not a part of the container
• Aggregate object can exist independently

Example I
Furniture is not an intrinsic part of room
Furniture can be shifted to another room, and so can exist independent of a particular room

Example II
A plant is not an intrinsic part of a garden
It can be planted in some other garden, and so can exist independent of a particular garden

Code-Example: Company has Employee


#include <iostream>

using namespace std;


class Employee{ private:
int id;
string EmpName;
public:
Employee(int id=0,string name=""){

this->id=id;
this->EmpName=name;
}
void show(){ cout<<"\
nEmployee ID:"<<id;
cout<<"\n Employee Name:"<<EmpName;

}
};
class company{
private:
string cmpName;
Employee *emp;
public:
company(string name="")
{ cmpName=name;
}
void setEMp(Employee *emp)
{ this->emp=emp;
}
void display(){
cout<<"The Company\t "<<cmpName<<"\t has Employee \n";
emp->show();
}

};
int main()
{
company cmp("Bata");
Employee emp(1234,"Ali
Ahmed"); cmp.setEMp(&emp);
cmp.display();
return 0;}

Access Specifier and Types of Inheritance


C++ provides us with protected access specifier for these sorts of situations; protected access
specifier ensures that function in base class is accessible in derived class of this base class and
not outside of this class. So we can say that scope of protected access specifier is somewhere in
between private and public access specifiers it is similar to private in the sense that it doesn’t
allow the external world to access protected member and it is similar to public access specifier in
the sense that it ensures that protected member is accessible in derived classes of the protected
member class.
Protected members of a class cannot be accessed outside the class but only in the derived class of
that class. Protected members of base class become protected member of derived class.
Example:
#include <iostream> class B:public A{
int b;
using namespace std; public:
class A{
B(){
protected: b=0;
int a; }
public: void setb(){
A(){ b=8;
a=0;
} }
void seta(){ void show(){
a=8; cout<<"\n"<<b*a; //Accessing protected
} Datamember of base class
void display(){ }
cout<<"\n"<<a;
} };

};
int main()
{
B b;
b.seta();
b.setb();
b.display();
b.show();
return 0;
}
Another important use of access specifiers is their role in the inheritance process. Considering
access specification in C++, inheritance can be private, protected, or public. Each type of inheritance has
specific rules to access base class’s data member(s), which have been explained below.
There are three types of inheritance
• Public
• Protected
• Private

If a class is derived from a base class with public specifier, then all public/protected member(s) of base
class become public/protected member(s) of derived class. However, private member(s) of base class are
never accessible from derived class directly.
If a class is derived from a base class with protected specifier, then all public/protected
member(s) of base class become protected member(s) of derived class. However, private
member(s) of base class are never accessible from derived class directly.

If a class is derived from a base class with private specifier, then all public/protected member(s)
of base class become private member(s) of derived class.

If the user does not specifies the type of inheritance then the default type is private Inheritance,

class Child: private Parent {…}


is equivalent to,
class Child: Parent {…}
We have seen public inheritance in previous lecture, now we see private and protected
inheritance in detail,
Implementation Protected inheritance
#include <iostream> class B:protected A{
int b;
using namespace std; public:
class A{
B(){
private: b=7;
int a; }
public: void show(){
A(){ display(); //solution
a=8; cout<<"\n"<<b;
} }
void display(){
cout<<"\n"<<a; };
}

};

int main()
{
B b;
// b.display(); // Error we can not access
b.show();
return 0;
}
Private inheritance
#include <iostream> class B:private
A{ int b;
using namespace std; class public:
A{
B():A(){
private: b=7;
int a; }
public: void show(){
A(){ display(); //solution cout<<"\
a=8; n"<<b;
} }
void display(){
cout<<"\n"<<a; };
}

};

class C:private int main()


B{ int c; {
public: C c;
C():B( c.print();
){ return 0;
c=6; }
}
void print(){
//display();//Error not access
show();
cout<<"\n"<<c;
}

};
Private data members will NOT be accessible in any derived class or in main function.

Protected data members will become private data members in case of private inheritance and protected data
members of derived class in case of protected inheritance.

Function overloading

Function Overloading is the availability of various functions within a class that differ from each other in
function signature i.e. various functions share same name with different parameter types or number of
parameters. Inheritance is not necessarily required to overload functions within a program.

Function Overriding
Function Overriding, there must exists inheritance relationship between classes (i.e. base and derived) and
functions’ signature are also required to be same in both parent and child class(es). However, derived
class(es) redefine function(s) having signature similar to base class’s function(s).

Polymorphism:
It is Combination of Two Greek Words
 Poly: Many
 Morphism: Forms

Polymorphism allows an object reference variable or an object pointer to reference objects of different
types and to call the correct member Functions, depending upon the type of object being referenced.
There are two types polymorphism
1. Static /Compile time Polymorphism
It is also known as Early Binding
Example:
Function overloading and Operator overloading
2. Dynamic /Run time Polymorphism
It is also known as Late Binding
Example:
Virtual Function

1. Static /Compile time Polymorphism


#include <iostream> class Derive:public
Base{ public:
using namespace std; void func(){
class Base{ cout<<"Derive class function";
public: }
void func(){ };
cout<<"Base Class Function"; int main()
} {
Base *bptr;
}; Derive d;
bptr=&d;
bptr-
>func();
return 0;}

Check the behavior of Base class pointer object, Even we are giving address of derive class
object but it is calling to base class function .This is because the compiler checks static type of
the object (means which class type object is calling the object) at compile and call function
according to the type of object. When function is call by seeing the type of the object this is
called compile time, early or static binding.

You have seen the problem, let’s dug to solution.


2. Dynamic /Run time Polymorphism

#include <iostream> class Derive:public


using namespace std; Base{ public:
class Base{ void func(){
public: cout<<"\nDerive class function";
virtual void func(){ cout<<"\ }
nBase Class Function"; };
int main()
} {
Base *bptr;
}; Derive dev;
bptr=&dev;
bptr->func();
return 0;
}

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.

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;
};
Lab Manual: Data Structures and Algorithms

Lab Tasks

Task 1:
Consider a base class named Employee and its derived classes HourlyEmployee and
PermanentEmployee while taking into account the following criteria.

 Employee class has two data fields i.e. a name (of type string) and specific
empID (of type integer)
 Both classes (HourlyEmployee and PermanentEmployee) have an attribute
named hourlyIncome
 Both classes (HourlyEmployee and PermanentEmployee) have three-argument
constructor to initialize the hourlyIncome as well as data fields of the base class
 Class HourlyEmployee has a function named calculate_the_hourly_income to
calculate the income of an employee for the actual number of hours he or she
worked. One hour income is Rs. 150
 Similarly, PermanentEmployee class has function named calculate_the_income
to calculate the income of an employee that gets paid the salary for exact 240
hours, no matter how many actual hours he or she worked. Again, one hour
salary is Rs. 150.

Implement all class definitions with their respective constructors to initialize all data
members and functions to compute the total income of an employee. In the main()
function, create an instance of both classes (i.e. HourlyEmployee and
PermanentEmployee) and test the working of functions that calculate total income of
an employee.
Task 2:
The person has birthday. The person class has following behavior and attributes
 He has attributes name and city, Birthday
 Design parameterize constructor to initialize with user defined values
 Design Display function to show the person
information. The

Birthday class has following attributes

 Attributes are day, month and year.


 Design Nullary constructor to set the default values.
 Design parameterize constructor to initialize with user defined values.
 Design show function to show the person information.
Implement to these classes and illustrate the relationship.
Task 3:
The Teacher has a course. The Teacher has following type of attributes
 He has id, name and course name

Department of Computer Science, UMT, Lahore. 25


Lab Manual: Data Structures and Algorithms
 Design default argument constructor to set the default values
 Getter functions to get the
information
The course has following type of attributes
 Name and publication date
 Design default argument constructor to set the default values
 Design Display function to show the Course information.

Implement to these classes and illustrate the relationship.

Task 4:
NoteBook is the base class that holds
 data fields named manufacturerID (of integer type) and manufacturerName (of
string type)
 A two-argument constructor to initialize data-fields with user-defined values
 Appropriate accessor and mutator functions to set and get values of data
fields Derive two classes from the NoteBook class:
 ENotebook, which contains an attribute size of integer type and a setter member
function to set size value
 PaperNoteBook, which contains an instance variable named totalPages along
with a member function to
 set total number of pages in a certain paper notebook object
 Both derived classes have function display to show all data field values (including
values inherited from the base class).
In the main() function, create objects of ENoteBook and PaperNoteBook classes and show the
advantages of using protected access specifier.

Tasks 5

Consider a class Computer having


 Two fields (i.e. companyName, price) and
 A single virtual function named show()

A class named Desktop inherits Computer class and adds fields representing
 color, monitor size, and processor type and
 Override function named show() to display values of its all attributes

A class named Laptop inherits Computer class and adds fields representing
 color, size, weight, and processor type and
 Override function named show() to display values of its all attributes

Write a main() function that instantiates objects of derived classes to access respective show() function
using dynamic binding.
Task 6:
ADT: NumDays

Department of Computer Science, UMT, Lahore. 26


Lab Manual: Data Structures and Algorithms
Design a class called NumDays. The class’s purpose is to store a value that represents a number of
work hours and convert it to a number of days.
For example, 8 hours would be converted to 1 day, 12 hours would be converted to 1.5 days, and 18
hours would be converted to 2.25 days. The class should have a constructor that accepts a number of
hours, as well as member functions for storing and retrieving the hours and days.
The class should also have the following overloaded operators:
Addition operator (+): When two NumDays objects are added together, the overloaded + operator
should return the sum of the two objects’ hours members.
Subtraction operator (–): When one NumDays object is subtracted from another, the overloaded –
operator should return the difference of the two objects’ hours members.
Prefix and postfix increment operators (++): These operators should increment the number of hours
stored in the object. When incremented, the number of days should be automatically recalculated.
Prefix and postfix decrement operators (--): These operators should decrement the number of hours
stored in the object. When decremented, the number of days should be automatically recalculated.

Department of Computer Science, UMT, Lahore. 27

You might also like