Unit 3
Unit 3
Single
Multiple
Hierarchical
Multilevel
Hybrid
Single Inheritance
A derived class with only one base class.
B
Multiple Inheritance
A derived class with several base classes.
A B
C
Hierarchical Inheritance
A traits of one class may be inherited by more than one class.
B C D
Multilevel Inheritance
The mechanism of deriving a class from another derived class.
C
Hybrid Inheritance
The mechanism of deriving a class by using a mixture of different
methods.
B C
D
Derived Classes
A derived class can be defined by specifying its relationship with
the base class in addition to its own details.
class derived-class-name : visibility-mode base-class-name
};
Class ABC: public XYZ //public derivation
{
Members of ABC
};
Class ABC: XYZ //private derivation
{
Members of ABC
};
Visibility Modes- private & public
When a base class is privately derived by a derived
class, “public members” of the base class become
“private members” of the derived class.
Therefore the members of the derived class can only
access the public members of the base class.
They are inaccessible to the objects of the derived class.
No member of the base class is accessible to the objects
of the derived class.
When a base class is publicly inherited, ”public
members” of the base class become the “public
members” of the derived class.
They are accessible to the objects of the derived class.
Note:
In both the cases(publicly/privately
inherited), the private members are not
inherited and therefore, the private
members of a base class will never
become the members of its derived class.
Advantage of Inheritance- Reusability
In inheritance, some of the base class data elements and
member functions are inherited into the derived class.
B
Inheriting with Public visibility
#include <iostream>
using namespace std;
class Account {
public:
float salary = 60000;
void display()
{
cout<<“I am function of class Account”;
}
};
class Programmer: public Account {
public:
float bonus = 5000;
};
int main(void) {
Programmer p1;
cout<<"Salary: "<<p1.salary<<endl;
cout<<"Bonus: "<<p1.bonus<<endl;
p1.display();
return 0;
}
Inheriting with private visibility
#include <iostream> {
using namespace std; getab();
class first { c=b*geta();
int a; }
public: void display()
int b; {
void getab(){ cout<<"\na = "<<geta();
a=5; cout<<"\nb = "<<b;
b=10; cout<<"\nc = "<<c<<"\n";
} }
int geta(){ };
return a; int main()
} {
void showa(){ second s1;
cout<<"\na = "<<a<<"\n"; s1.getab(); //gives error
} s1.b=20; //gives error
}; s1.mul();
class second: private first { s1 .showa(); //gives error
int c; s1.display();
public: return 0;
void mul() }
Making a Private Member Inheritable
The private member is not inheritable. If we
modify the visibility mode by making it public,
this takes away the advantage of data hiding
C++ introduces a third visibility modifier, i.e.,
protected.
A member declared as “protected” is accessible
by the member functions within its class and any
class immediately derived from it.
It can not be accessed by the functions outside
these two classes.
Making a Private Member Inheritable continue …
class alpha
{
private : // optional
……… // visible to the member within its class
………
protected :
……… // visible to member functions
……… // of its own and immediate derived
class
public :
……… // visible to all functions
……… // in the program
};
Protected Derivation
Class B
Protected
Private Private
Protected Protected
Public Public
Class X : public D1, protected D2
Private
Protected
Public
Visibility
protected
fy2
fx2 data
friend of X
class Z
Function 1
fz1 friend of X
fz2
Inherited from X
Multilevel Inheritance
The class A serves as a base
class for the derived class B,
which in turn serves as a base
class for the derived class C.
Base Class A
In Multiple Inheritance
Ambiguity Resolution in Inheritance continue …
In Single Inheritance
#include <iostream>
using namespace std;
class A {
int a;
public:
void show() {
cout << "I am class A!" << endl;
}};
class B {
int b;
public:
void show() {
cout << "I am class B" << endl;
}};
class C : public A, public B {
int c;
public:
void show3() {
cout << "I am class C " << endl;
}};
int main() {
C c1;
c1.show();
return 0;
}
To remove ambiguity:
c1.A::show();
Function overriding
Suppose, the same function is defined in both the 13. }
derived class and the based class. Now if we call
14. };
this function using the object of the derived class,
the function of the derived class is executed. In the above case, the function of the derived class
overrides the method of the base class. Therefore, call
This is known as function overriding in C++.
to the display() function will simply call the function
The function in derived class overrides the function defined in the derived class.
in base class.
If we want to invoke the base class function, we can
1. class A { use the class resolution operator.
2. public: 15. int main()
3. void display()
16. {
4. {
17. B b;
5. cout<<Class A;
6. } 18. b.display();
7. }; 19. // Calling the display() function of B class.
8. class B : public A { 20. b.B :: display();
9. public: 21. // Calling the display() function defined in B class.
10. void display() 22. }
11. {
12. cout<<Class B;
Hierarchical Inheritance
Account
Inheritance support hierarchical
design of a program.
student
Applying Two or
more types of
inheritance
test sports
together.
result
Aggregation (has – a - relationship)
Aggregation is a process in which one class defines another 19. string name;
class as any entity reference. It is another way to reuse the
20. Employee(int id, string name, Address* address)
class. It is a form of association that represents HAS-A
relationship. 21. {
1. #include <iostream> 22. this->id = id;
2. using namespace std; 23. this->name = name;
3. class Address { 24. this->address = address;
4. public: 25. }
5. string addressLine, city, state; 26. void display()
6. Address(string addressLine, string city, string state) 27. {
7. { 28. cout<<id <<" "<<name<< " "<<
8. this->addressLine = addressLine; 29. address->addressLine<< " "<< address-
>city<< " "<<address->state<<endl;
9. this->city = city;
30. }
10. this->state = state;
31. };
11. }
32. int main(void) {
12. };
33. Address a1= Address("C-146, Sec-15","Noida","UP");
13. class Employee
34. Employee e1 = Employee(101,"Nakul",&a1);
14. {
35. e1.display();
15. private:
36. return 0;
16. Address* address; //Employee HAS-A Address
37. }
17. public:
18. int id;
Composition vs. Classification
Association is a relationship between two objects. It’s denoted by “has-a”
relationship. In this relationship all objects have their own lifecycle and there is no
owner. Let’s take an example of Teacher and Student. Multiple students can
associate with single teacher and single student can associate with multiple
teachers, but there is no ownership between the objects and both have their own
lifecycle.
Aggregation and Composition are subsets of association meaning they are
specific cases of association.
• In both aggregation and composition object of one class "owns" object of
another class.
• But there is a subtle difference. In Composition the object of class that is owned
by the object of it's owning class cannot live on it's own(Also called "death
relationship"). It will always live as a part of it's owning object where as
in Aggregation the dependent object is standalone and can exist even if the
object of owning class is dead.
• Consider the example of a Car and an engine that is very specific to that car
(meaning it cannot be used in any other car). This type of relationship
between Car and SpecificEngine class is called Composition. Now consider
class Car and class Wheel. Car needs a Wheel object to function. Meaning the Car
object owns the Wheel object but we cannot say the Wheel object has no
significance without the Car Object. It can very well be used in a Bike, Truck or
different Cars Object.
Composition vs. Classification
An object is a basic unit of Object-Oriented Programming and represents real-
life entities. Complex objects are objects that are built from smaller or a
collection of objects. For example, a mobile phone is made up of various
objects like a camera, battery, screen, sensors, etc. This process of building
complex objects from simpler ones is called object composition.
Inheritance/Classification is the methodology by which an object acquires
the characteristics of one or more other objects. It is one of the most powerful
tools in implementing code reusability in OOP. When using inheritance, a new
class can be created by establishing parent-child relationships with existing
classes.
Object composition is an alternative to class inheritance. Using an object within
another object is known as composition. On many occasions you’d want to use
an object as a field within another class because it’s easy to create complex
classes using previously written, well-designed classes as components.
While both inheritance and composition promote code reusability, With
inheritance, you can create classes that derive their attributes from existing
classes so while using inheritance to create a class, you can expand on an
existing class but it can be done at compile time. On the contrary, using an
object within another object is known as composition and it can be modified
dynamically.
Virtual Base Classes
Here the result class has two direct base classes test and
sports which themselves have a common base class
student.
The result inherits the traits of student via two separate student
paths.
All the public and protected members of student are
inherited into result twice, first via test and again via
sports.
test sports
This means result class have duplicate set of members
inherited from student.
When any data / function member of class student is
accessed by an object of class result, ambiguity arises as
to which data/function member would be called?
To resolve this ambiguity when class student is inherited result
in both class test and class sports, it is declared as virtual
base class by placing a keyword virtual.
So, it can inherit directly as shown by the broken line.
The student class is referred to as indirect base class.
Virtual Base Classes
continue …
class student
{
………
}; student
class test : virtual public student
{
……… test sports
};
class sports : public virtual student
{
……… result
};
class result : public test, public sports
{
………\
};
#include <iostream>
using namespace std;
class A {
public:
void show()
{
cout << "Hello from A \n";
}
};
class B : public virtual A {
};
class C : public virtual A {
};
class D : public B, public C {
};
int main()
{
D object;
object.show();
}
Constructor and destructor in derived classes
Default Constructors in Derived Classes
If no base class constructor takes any arguments,
the derived class need not have a constructor
function.
When both the derived and base class contain
constructors, the base constructor is executed first
and then the constructor in the derived class is
executed.
In the case of the default constructor, it is implicitly accessible from
parent to the child class
#include <iostream>
using namespace std;
class parent //parent class{
public:
parent() //constructor
{
cout << "Parent class Constructor\n";
}
~parent()//destructor
{
cout << "Parent class Destructor\n";
}};
class child : public parent//child class{
public:
child() //constructor {
cout << "Child class Constructor\n";
}
~ child() //destructor
{
cout << "Child class Destructor\n";
}};
int main(){
child c;
return 0;
}
Parameterized Constructors in Derived Classes
If any base class contains a constructor with one or more arguments,
then it is mandatory for the derived class to have a constructor and
pass the arguments to the base class constructors.
Parameterized constructors are not accessible to the derived class
automatically, for this reason, an explicit call has to be made in the
child class constructor to access the parameterized constructor of the
parent class to the child class using the following syntax:
<class_name>:: constructor(arguments)
The constructor of the derived class receives the entire list of values as
its arguments and passes them on to the base constructors in the order
in which they are declared in the derived class.
The base constructors are called and executed before executing the
statements in the body of the derived constructor.
#include <iostream>
using namespace std;
class parent { //parent class
public:
parent(int a) // parent constructor
{
cout << "Parent class Constructor\n" << a<<“\n”;
}
~parent() // parent destructor
{
cout << "Parent class Destructor\n";
}};
class child : public parent { //child class
public:
child(int x, int a):parent(a) //child class constructor.x for child and a for parent class
parameter
{
cout << "Child class Constructor\n"<<x<<“\n”;
}
~ child() //child class destructor
{
cout << "Child class Destructor\n";
}};
int main(){
child c(10,40);
return 0;
}
Constructor call in multiple
inheritance constructors
class C: public A, public B;
Constructors are called upon the order in which they are inherited
First class A constructors are executed followed by class B
constructors, then class C constructors.
Note: Whenever you are using the parameterized constructor in the
parent class it is mandatory to define a default constructor explicitly
Defining Derived Constructors
continue …
Since the derived class takes the responsibility of supplying initial values to its base classes, we supply
the initial values that are required by all the classes together, when a derived class object is
declared.
base1(arglist1),
base2(arglist2),
baseN(arglistN)
The header line of derived-constructor function contains two parts separated by a colon
(:).
The first part provides the declaration of the arguments that are passed to the
derived constructor.
The second part lists the function calls to the base constructors.
Polymorphism
The term "Polymorphism" is the combination of "poly" +
"morphs" which means many forms.
That is, the same entity (function or operator) behaves
differently in different scenarios.
For example,
The + operator in C++ is used to perform two specific
functions. When it is used with numbers (integers and floating-
point numbers), it performs addition. And when we use the +
operator with strings, it performs string concatenation.
Polymorphism allows us to create consistent code.
Types of polymorphism
There are two ways of implementing polymorphism in C++
1. Compile time polymorphism : In this, the compiler knows which
function to execute before the program is compiled. It is implemented
as
a) Operator Overloading
b) Function Overloading
2. Run time polymorphism : In this, the function call is not resolved
by the compiler, but it is resolved in the runtime instead. It is
implemented as
a) Function overriding
b) Virtual functions
Virtual functions
One of the key features of class inheritance is that a pointer to a derived class
is type-compatible with a pointer to its base class.
VIRTUAL means existing in appearance but not in reality
VIRTUAL FUNCTION means function exists in class but can’t be used.
A virtual function (also known as virtual methods) is a member function that
is declared within a base class and is re-defined (overridden) by a derived
class. When you refer to a derived class object using a pointer or a reference to
the base class, you can call a virtual function for that object and execute the
derived class’s version of the method.
Unlike a non-virtual function, when a virtual function is overridden the most-
derived version is used at all levels of the class hierarchy, rather than just the
level at which it was created. Therefore if one method of the base class calls a
virtual method, the version defined in the derived class will be used instead of
the version defined in the base class.
This is in contrast to non-virtual functions, which can still be overridden in a
derived class, but the "new" version will only be used by the derived class and
below, but will not change the functionality of the base class at all.
Need for virtual functions
A virtual function in C++ helps ensure you call the correct function via a
reference or pointer. The C++ programming language allows you only to use a
single pointer to refer to all the derived class objects. Since the pointer refers
to all the derived objects, calling it will consistently execute the function in the
base class. You can overcome this challenge with a virtual function in C++ as it
helps execute the virtual version of the derived class, which is done at the run-
time.
Rules for virtual functions
• The functions cannot be static
• Virtual functions in C++ needs to be a member of some other class (base
class)
• They can be a friend function of another class
• The prototype of these functions should be the same for both the base and
derived class
• Virtual functions are accessible using object pointers
• Redefining the virtual function in the derived class is optional, but it needs to
be defined in the base class
• The function call resolving is done at run-time
#include <iostream> The output function gave
using namespace std;
the result “Output Derived
class Base{
public: class,” and the Derived
virtual void Output(){ function gave the result
cout << "Output Base class" << endl;
} “Display Base class”. That’s
void Display(){ because the pointer of the
cout << "Display Base class" << endl;
}
base class referred to the
}; virtual output function of
class Derived : public Base{
the derived class, and the
public: non-virtual display function
void Output(){ of the base class.
cout << "Output Derived class" << endl;
}
void Display()
{
cout << "Display Derived class" << endl;
}
};
int main(){
Base* bpointr;
Derived dpointr;
bpointr = &dpointr;
bpointr->Output(); // virtual function binding
bpointr->Display(); // Non-virtual function binding
}
For reference: Virtual Function in C++ | C++ Tutorial for Beginners - YouTube
Compile time polymorphism Run time polymorphism
The function to be invoked is The function to be invoked is
known at the compile time. known at the run time.
It is also known as overloading, It is also known as overriding,
early binding and static binding. Dynamic binding and late binding.
It is less flexible as mainly all the It is more flexible as all the things
things execute at the compile execute at the run time.
time.
Pure virtual functions
A pure virtual function (or abstract function) in C++ is a virtual function for which we
don’t have an implementation, we only declare it.
A pure virtual function is declared by assigning 0 in the declaration.
It is also known as the do-nothing function as it does not perform any task. It is only
used as a placeholder and does not contain any function definition (do-nothing
function).
syntax:
Virtual void function_name() = 0;
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.
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 functions are used if a function doesn't have any use in the base class
but the function must be implemented by all its derived classes
Similarities between virtual function and pure virtual function
1. These are the concepts of Run-time polymorphism.
2. Prototype i.e. Declaration of both the functions remains the same throughout the
program.
3. These functions can’t be global or static.
#include <iostream>
using namespace std;
class Base
{
public:
virtual void show() = 0;
};
class Derived : public Base
{
public:
void show()
The base class contains
{
cout << "Derived class is derived from the base class." << endl;
the pure virtual function.
}
Therefore, the base class
}; is an abstract base class.
int main() We cannot create the
{ object of the base class.
Base *bptr;
Derived d;
bptr = &d;
bptr->show();
return 0;
}
Abstract class
A class that contains a pure virtual function is known as an abstract
class.
Sometimes implementation of all functions cannot be provided in a
base class because we don’t know the implementation. Such a class
is called an abstract class.For example, let Shape be a base class.
We cannot provide the implementation of function draw() in Shape,
but we know every derived class must have an implementation of
draw().
A class is abstract if it has at least one pure virtual function.
We can have pointers and references of abstract class type.
If we do not override the pure virtual function in the derived
class, then the derived class also becomes an abstract class.
An abstract class can have constructors that can be called by
the derived class.
We cannot create objects of an abstract class. However, we
can derive classes from them, and use their data members
and member functions (except pure virtual functions).
#include <iostream>
using namespace std; // Derived class
// Abstract class class Circle : public Shape {
class Shape { public:
protected: float calculateArea() {
float dimension; return 3.14 * dimension * dimension;
public: }
void getDimension() { };
cin >> dimension; int main() {
} Square square;
Circle circle;
// pure virtual Function cout << "Enter the length of the square: ";
virtual float calculateArea() = 0; square.getDimension();
}; cout << "Area of square: " <<
square.calculateArea() << endl;
// Derived class
cout << "\nEnter radius of the circle: ";
class Square : public Shape {
circle.getDimension();
public:
cout << "Area of circle: " <<
float calculateArea() {
circle.calculateArea() << endl;
return dimension * dimension;
}
return 0;
};
}