You are on page 1of 55

Object-Oriented

Programming: Inheritance
Introduction

• Inheritance
– The capability of a class to derive properties and
characteristics from another class is called Inheritance
– New classes created from existing classes
– Absorb attributes and behaviors.
• Base class
– A class that is used to create (or derive) another class is
called the base class. Also called a super class or parent
class.
• Derived class
– Class that inherits data members and member functions
from a previously defined base class. Also, called as child
class or sub class.
Introduction
• Inheritance
– Software reusability
– Create new class from existing
class
• Absorb existing class’s data and
behaviors
• Enhance with new capabilities
– Subclass extends superclass
• Subclass
– More specialized group of objects
– Behaviors inherited from superclass
» Can customize
– Additional behaviors
Inheritance vs Composition
• Inheritance is an "is-a" relationship. Composition is a "has-a".
• Flexibility
– When you use Inheritance, you have to define which class you are extending in
code, it cannot be changed at runtime, but with Composition you just define a
Type which you want to use, which can hold its different implementation.
• Limited code reuse with Inheritance
– Inheritance you can only extend one class, which means you code can only
reuse just one class (except multiple inheritance), not more than one. If you
want to leverage functionalities from multiple class, you must use
Composition.
• Encapsulation
– Though both Inheritance and Composition allows code reuse, Inheritance
breaks encapsulation because in case of Inheritance, sub class is dependent
upon super class behavior. If parent classes changes its behavior than child
class is also get affected.
Introduction

• Inheritance
– Single Inheritance
• Class inherits from one base class

– Multiple Inheritance
• Class inherits from multiple base classes

– Multilevel Inheritance
• A derived class with one base class and that
base class is a derived class of another
Introduction

• Inheritance
– Hierarchical Inheritance
• Multiple derived classes with same base
class

– Hybrid Inheritance
• Combination of multiple and
hierarchical inheritance

– Multipath Inheritance
• A derived class with two base classes and
these two base classes have one common
base class
Base and Derived Classes

Inheritance hierarchy for university CommunityMembers


Base and Derived Classes

Inheritance hierarchy for Shapes


9

Software Engineering Observation

• Methods of a subclass cannot directly access


private members of their superclass.
• A subclass can change the state of private
superclass instance variables only through non-
private methods provided in the superclass and
inherited by the subclass.
• Declaring private instance variables helps
programmers test, debug and correctly modify
systems.
10

Software Engineering Observation

• If a subclass could access its superclass’s


private instance variables, classes that inherit
from that subclass could access the instance
variables as well.
• This would propagate access to what should be
private instance variables, and the benefits of
information hiding would be lost.
Base and Derived Classes

• Implementation of public inheritance

class CommissionWorker : public Employee {


...
};

Class CommissionWorker inherits from class Employee


– friend functions not inherited
– private members of base class not accessible from derived
class
Protected Members

• protected inheritance
– Intermediate level of protection between public and
private inheritance
– Derived-class members can refer to public and
protected members of the base class simply by using the
member names
– Note that protected data “breaks” encapsulation
• protected access
– Intermediate level of protection between public and private
– protected members accessible by
• superclass members
• subclass members
• Class members in the same package
– Subclass access to superclass member
• Keyword super and a dot (.)
Public, Private, and Protected Inheritance
Public, Private, and Protected Inheritance

class base
{
public:
int x;
protected:
int y;
private:
int z;
};
Public, Private, and Protected Inheritance
class publicDerived: public base
{
// x is public // y is protected // z is not accessible from
publicDerived
};
class protectedDerived: protected base
{ // x is protected // y is protected // z is not accessible from
protectedDerived
};
class privateDerived: private base
{ // x is private // y is private // z is not accessible from
privateDerived
};
Public Inheritance
class Base int main()
{ {
public: Base base;
int m_public; base.m_public = 1; // okay: m_public is
private: public in Base
int m_private; base.m_private = 2; // not okay: m_priva
protected: te is private in Base
int m_protected; base.m_protected = 3; // not okay: m_pr
}; otected is protected in Base
class Pub: public Base // public inheritance
{ Pub pub;
public: pub.m_public = 1; // okay: m_public is p
Pub() ublic in Pub
{ pub.m_private = 2; // not okay: m_privat
m_public = 1; // okay: m_public was e is inaccessible in Pub
inherited as public pub.m_protected = 3; // not okay: m_pro
m_private = 2; // not okay: m_private is in tected is protected in Pub
accessible from derived class return 0;
m_protected = 3; // okay: m_protected was }
inherited as protected
}
};
Private Inheritance (Default Inheritance)
class Base int main()
{ {
public: Base base;
int m_public; base.m_public = 1; // okay: m_public is
private: public in Base
int m_private; base.m_private = 2; // not okay: m_priva
protected: te is private in Base
int m_protected; base.m_protected = 3; // not okay: m_pr
}; otected is protected in Base
class Pri: private Base // note: private inherita
nce Pri pri;
{ pri.m_public = 1; // not okay: m_public i
public: s now private in Pri
Pri() pri.m_private = 2; // not okay: m_private
{ is inaccessible in Pri
m_public = 1; // okay: m_public is now pri pri.m_protected = 3; // not okay: m_prot
vate in Pri ected is now private in Pri
m_private = 2; // not okay: derived classes return 0;
can't access private members in the base class }
m_protected = 3; // okay: m_protected is
now private in Pri
}};
Single Inheritance Example
// inheritance.cpp class derive : public base
#include <iostream> //single derived class
using namespace std; {
class base //single base class private:
{ int y;
public: public:
int x; void readdata()
void getdata() {
{ cout << "Enter the value of
y = "; cin >> y;
cout << "Enter the value of x =
"; cin >> x; }
} void product()
}; {
cout << "Product = " << x * y;
} };
Single Inheritance Example
int main() Output
{
derive a; //object of Enter the value of x = 3
derived class Enter the value of y = 4
a.getdata(); Product = 12
a.readdata();
a.product();
return 0;
} //end of program
Multiple Inheritance Example
#include <iostream> class C: public A, public B {
using namespace std; public:
class A { int c = 20;
public: C() {
int a = 5; cout << "Constructor for class
A() { C" << endl;
cout << "Constructor for class cout<<"Class C inherits from
A" << endl; class A and class B" << endl;
} }};
}; int main() {
class B { C obj;
public: cout<<"a = "<< obj.a <<endl;
int b = 10; cout<<"b = "<< obj.b <<endl;
B() { cout<<"c = "<< obj.c <<endl;
cout << "Constructor for class return 0;
B" << endl; }
}};
Multilevel Inheritance Example
// inheritance.cpp class derive2 : public derive1
#include <iostream> { private:
using namespace std; int z;
class base //single base class public:
{public: void indata()
int x; {
void getdata() { cout << "\nEnter value of
cout << "Enter value of z= "; cin >> z;
x= "; cin >> x;}}; }
class derive1 : public base void product()
{public: {
int y; cout << "\nProduct= "
void readdata(){ << x * y * z;
cout << "\nEnter value }
of y= "; cin >> y; };
}
};
Multilevel Inheritance Example
int main() Output
{
derive2 a; //object of Enter value of x= 2
derived class
a.getdata(); Enter value of y= 3
a.readdata();
a.indata(); Enter value of z= 3
a.product();
return 0; Product= 18
} //end of program
Hierarchical Inheritance Example
// hierarchial inheritance.cpp class C : public A //C is also
#include <iostream> derived from class base
using namespace std; { public:
class A //single base class void sum(){
{ public: cout << "\nSum= " << x + y;
int x, y; }};
void getdata() { int main()
cout << "\nEnter value {
of x and y:\n"; cin >> x >> y;}}; B obj1; //object of derived
class B : public A //B is derived class B
from class base C obj2; //object of derived
{ public: class C
void product(){ obj1.getdata();
cout << "\nProduct= " obj1.product();
<< x * y; obj2.getdata();
} obj2.sum();
}; return 0;
} //end of program
Hierarchical Inheritance Example
Output

Enter value of x and y:


2
3
Product= 6
Enter value of x and y:
2
3
Sum= 5
Hybrid Inheritance Example
// hybrid inheritance.cpp class D : public B, public C //D is
#include <iostream> derived from class B and class C
using namespace std; { public:
class A void sum()
{ public: {
int x; }; cout << "Sum= " << x
class B : public A + y; }};
{ public:
B() { int main()
x = 10; }}; { D obj1; //object of derived
class D
class C
obj1.sum();
{ public:
return 0;
int y;
} //end of program
C() {
y = 4;
Output
}};
Sum= 14
Protected data member in Inheritance
#include <iostream> int main(void) {
using namespace std; Rectangle Rect;
// Base class
class Shape { Rect.setWidth(5);
public: Rect.setHeight(7);
void setWidth(int w) {
width = w; } // Print the area of the object.
void setHeight(int h) { cout << "Total area: " <<
height = h; } Rect.getArea() << endl;
protected:
int width; return 0;
int height; }; }
// Derived class
class Rectangle: public Shape {
public:
int getArea() {
return (width * height); }};
Overriding Base-Class Members in a Derived
Class

• To override a base-class member function


– In derived class, supply new version of that function
• Same function name, different definition
– The scope-resolution operator may be used to access the base
class version from the derived class
1 // Fig. 19.5: employ.h
2 // Definition of class Employee
3 #ifndef EMPLOY_H
4 #define EMPLOY_H
5
6 class Employee {
7 public:
8 Employee( const char *, const char * ); // constructor
9 void print() const; // output first and last name
10 ~Employee(); // destructor
11 private:
12 char *firstName; // dynamically allocated string
13 char *lastName; // dynamically allocated string
14 }; // end class Employee
15
16 #endif

17 // Fig. 19.5: employ.cpp


18 // Member function definitions for class Employee
19 #include <iostream>
20
21 using std::cout;
22
23 #include <cstring>
24 #include <cassert>
25 #include "employ.h"
26
27 // Constructor dynamically allocates space for the
28 // first and last name and uses strcpy to copy
29 // the first and last names into the object.
30 Employee::Employee( const char *first, const char *last )
31 {
32 firstName = new char[ strlen( first ) + 1 ];
33 assert( firstName != 0 ); // terminate if not allocated
34 strcpy( firstName, first );
35
36 lastName = new char[ strlen( last ) + 1 ];
37 assert( lastName != 0 ); // terminate if not allocated
38 strcpy( lastName, last );
39 } // end Employee constructor
40
41 // Output employee name
42 void Employee::print() const
43 { cout << firstName << ' ' << lastName; }
44
45 // Destructor deallocates dynamically allocated memory
46 Employee::~Employee()
47 {
48 delete [] firstName; // reclaim dynamic memory
49 delete [] lastName; // reclaim dynamic memory
50 } // end Employee destructor
51 // Fig. 19.5: hourly.h
52 // Definition of class HourlyWorker
53 #ifndef HOURLY_H
54 #define HOURLY_H
55
56 #include "employ.h"
57
58 class HourlyWorker : public Employee {
59 public:
60 HourlyWorker( const char*, const char*, double, double );
61 double getPay() const; // calculate and return salary
62 void print() const; // overridden base-class print
63 private:
64 double wage; // wage per hour
65 double hours; // hours worked for week
66 }; // end class HourlyWorker
67
68 #endif

69 // Fig. 19.5: hourly.cpp


70 // Member function definitions for class HourlyWorker
71 #include <iostream>
72
73 using std::cout;
74 using std::endl;
75
76 #include <iomanip>
77
78 using std::ios;
79 using std::setiosflags;
80 using std::setprecision;
81
82 #include "hourly.h"
83
84 // Constructor for class HourlyWorker
85 HourlyWorker::HourlyWorker( const char *first,
86 const char *last,
87 double initHours, double initWage )
88 : Employee( first, last ) // call base-class constructor
89 {
90 hours = initHours; // should validate
91 wage = initWage; // should validate
92 } // end HourlyWorker constructor
93
94 // Get the HourlyWorker's pay
95 double HourlyWorker::getPay() const { return wage * hours; }
96
97 // Print the HourlyWorker's name and pay
98 void HourlyWorker::print() const
99 {
100 cout << "HourlyWorker::print() is executing\n\n";
101 Employee::print(); // call base-class print function
102
103 cout << " is an hourly worker with pay of $"
104 << setiosflags( ios::fixed | ios::showpoint )
105 << setprecision( 2 ) << getPay() << endl;
106 } // end function print
107 // Fig. 19.5: fig19_05.cpp
108 // Overriding a base-class member function in a
109 // derived class.
110 #include "hourly.h"
111
112 int main()
113 {
114 HourlyWorker h( "Bob", "Smith", 40.0, 10.00 );
115 h.print();
116 return 0;
117 } // end function main

HourlyWorker::print() is executing

Bob Smith is an hourly worker with pay of $400.00


Direct and Indirect Base Classes

• Direct base class


– Explicitly listed derived class’ header with the colon (:) notation
when that derived class is declared.
– class HourlyWorker : public Employee
• Employee is a direct base class of HourlyWorker
• Indirect base class
– Inherited from two or more levels up the class hierarchy
– class MinuteWorker : public HourlyWorker
• Employee is an indirect base class of MinuteWorker
Using Constructors and Destructors in Derived
Classes

• Base class initializer


– Uses member-initializer syntax
– Can be provided in the derived class constructor to call the
base-class constructor explicitly
• Otherwise base class’ default constructor called implicitly
– Base-class constructors and base-class assignment operators
are not inherited by derived classes
• However, derived-class constructors and assignment operators
can call still them
Using Constructors and Destructors in Derived
Classes

• Derived-class constructor
– Calls the constructor for its base class first to initialize its
base-class members
– If the derived-class constructor is omitted, its default
constructor calls the base-class’ default constructor
• Destructors are called in the reverse order of
constructor calls.
– Derived-class destructor is called before its base-class
destructor
1 // Fig. 19.7: point2.h
2 // Definition of class Point
3 #ifndef POINT2_H
4 #define POINT2_H
5
6 class Point {
7 public:
8 Point( int = 0, int = 0 ); // default constructor
9 ~Point(); // destructor
10 protected: // accessible by derived classes
11 int x, y; // x and y coordinates of Point
12 }; // end class Point
13
14 #endif
15 // Fig. 19.7: point2.cpp
16 // Member function definitions for class Point
17 #include <iostream>
18
19 using std::cout;
20 using std::endl;
21
22 #include "point2.h"
23
24 // Constructor for class Point
25 Point::Point( int a, int b )
26 {
27 x = a;
28 y = b;
29
30 cout << "Point constructor: "
31 << '[' << x << ", " << y << ']' << endl;
32 } // end Point constructor
33
34 // Destructor for class Point
35 Point::~Point()
36 {
37 cout << "Point destructor: "
38 << '[' << x << ", " << y << ']' << endl;
39 } // end Point destructor
40 // Fig. 19.7: circle2.h
41 // Definition of class Circle
42 #ifndef CIRCLE2_H
43 #define CIRCLE2_H
44
45 #include "point2.h"
46
47 class Circle : public Point {
48 public:
49 // default constructor
50 Circle( double r = 0.0, int x = 0, int y = 0 );
51
52 ~Circle();
53 private:
54 double radius;
55 }; // end class Circle
56
57 #endif
58 // Fig. 19.7: circle2.cpp
59 // Member function definitions for class Circle
60 #include <iostream>
61
62 using std::cout;
63 using std::endl;
64
65 #include "circle2.h"
66
67 // Constructor for Circle calls constructor for Point
68 Circle::Circle( double r, int a, int b )
69 : Point( a, b ) // call base-class constructor
70 {
71 radius = r; // should validate
72 cout << "Circle constructor: radius is "
73 << radius << " [" << x << ", " << y << ']' << endl;
74 } // end Circle constructor
75
76 // Destructor for class Circle
77 Circle::~Circle()
78 {
79 cout << "Circle destructor: radius is "
80 << radius << " [" << x << ", " << y << ']' << endl;
81 } // end Circle destructor
82 // Fig. 19.7: fig19_07.cpp
83 // Demonstrate when base-class and derived-class
84 // constructors and destructors are called.
85 #include <iostream>
86
87 using std::cout;
88 using std::endl;
89
90 #include "point2.h"
91 #include "circle2.h"
92
93 int main()
94 {
95 // Show constructor and destructor calls for Point
96 {
97 Point p( 11, 22 );
98 } // end block
99
100 cout << endl;
101 Circle circle1( 4.5, 72, 29 );
102 cout << endl;
103 Circle circle2( 10, 5, 5 );
104 cout << endl;
105 return 0;
106 } // end function main
Point constructor: [11, 22]
Point destructor: [11, 22]

Point constructor: [72, 29]


Circle constructor: radius is 4.5 [72, 29]

Point constructor: [5, 5]


Circle constructor: radius is 10 [5, 5]

Circle destructor: radius is 10 [5, 5]


Point destructor: [5, 5]
Circle destructor: radius is 4.5 [72, 29]
Point destructor: [72, 29]
Implicit Derived-Class Object to Base-Class
Object Conversion

• baseClassObject = derivedClassObject;
– This will work
• Remember, the derived class object has more members than the base
class object
– Extra data is not given to the base class
• derivedClassObject = baseClassObject;
– May not work properly
• Unless an assignment operator is overloaded in the derived class, data
members exclusive to the derived class will be unassigned
– Base class has less data members than the derived class
• Some data members missing in the derived class object
Implicit Derived-Class Object to Base-Class
Object Conversion

• Four ways to mix base and derived class pointers


and objects:
– Referring to a base-class object with a base-class pointer
• Allowed
– Referring to a derived-class object with a derived-class
pointer
• Allowed
– Referring to a derived-class object with a base-class pointer
• Possible syntax error
• Code can only refer to base-class members, or syntax error
– Referring to a base-class object with a derived-class pointer
• Syntax error
• The derived-class pointer must first be cast to a base-class
pointer
Implicit Derived-Class Object to Base-Class
Object Conversion
#include <iostream> int main() {
class Base { Derived* d = new Derived;
public: d->otherfunc(); // Derived::otherfunc
void func() d->func(); // Base::func
{
std::cout << "Base::func\n"; Base* b = new Base;
} b->func(); // Base::func
}; //b->otherfunc(); -- syntax error, no
otherfunc in Base
class Derived : public Base {
public: Base* db = new Derived;
void otherfunc() db->func(); // Base::func
{ // db->otherfunc(); -- syntax error, it
s t d : : c o u t < < doesn't know db is a Derived
"Derived::otherfunc\n"; } }
};
Implicit Derived-Class Object to Base-Class
Object Conversion
Derived::otherfunc
Base::func
Base::func
Base::func
Diamond Problem in Inheritance C++
• See the code below class receiver: public storable
{
class storable //this is the our base class public:
inherited by transmitter and receiver classes void read();
{ public: ...
storable(const char*); }
void read();
void write(); class radio: public transmitter,
~storable(); public receiver
private: {
.... } public:
class transmitter: public storable void read();
{ ....
public: }
void write();
... }
Diamond Problem in Inheritance C++
• Both transmitter and receiver classes are using the method
write() from the base class.
• When calling the method write() from a radio class object
the call is ambiguous.
• The compiler can't know which implementation of write()
to use.
• The one from the transmitter class or the one from the
receiver class.
Diamond Problem in Inheritance C++
• C++ allows us to solve this problem by using virtual inheritance.
• In order to prevent the compiler from giving an error we use the
keyword virtual when we inherit from the base class storable in
both derived classes:
class transmitter: public virtual storable
{ • When we use virtual inheritance, we
public: are guaranteed to get only a single
void read(); instance of the common base class.
... • In other words, the drive class will
} have only a single instance of
the base class, shared by both
class receiver: public virtual storable
the transmitter and receiver classes.
{
• By having a single instance of base, it
public: resolved the compiler's immediate
void read(); issue, the ambiguity, and the code will
... compile fine.
};
vtables
• In order to keep track of the single instance of the storable object,
the compiler will provide a virtual function table (vtable) for
classes transmitter and receiver (implicitly).
• When a radio object is constructed, it creates one storable
instance, a transmitter instance and a receiver instance.
• The transmitter and receiver classes have a virtual pointer in their
vtables that stores the offset to the storable class.
• When the transmitter class or the receiver class goes to access
any fields of the storable.
• It uses the virtual pointer in its vtable to find the storable object
and find the field in it.
vtables
• Every class that uses virtual functions (or is derived from a class
that uses virtual functions) is given it's own virtual table as a
secret data member.
• This table is set up by the compiler at compile time.
• A virtual table contains one entry as a function pointer for each
virtual function that can be called by objects of the class.
• Virtual TABLE is created even for classes that have virtual base
classes.
• In this case, the vtable has pointer to the shared instance of the
base class along with the pointers to the classe's virtual functions
if any.
vtables
_vptr :
• This vtable pointer or _vptr, is a hidden pointer added by the
Compiler to the base class, and this pointer is pointing to the
virtual table of that particular class.
• This _vptr is inherited to all the derived classes.
• Each object of a class with virtual functions transparently stores
this _vptr.
• Call to a virtual function by an object is resolved by following
this hidden _vptr.
vtables
#include<iostream.h> class D2: public Base
class Base {
{ public:
public: ~D2(){};
virtual void function1() virtual void function2()
{ {
cout<<"In function1\n";}; cout<< "In function2\n";
virtual void function2() }
{ };
cout<<“In function2\n";};
virtual ~Base(){}; int main()
}; {
D1 *d = new D1;;
class D1: public Base Base *b = d; b->function1();
{ b->function2();
public: }
~D1(){};
virtual void function1()
{
cout<<“In function1\n";};
};
Vtables and _vptr
Constructor and Destructor in Inheritance
#include <iostream>
using namespace std; class Child : public Parent1, public
class Parent1 Parent2
{ {
public: public:
Parent1() Child()
{ {
cout << "Inside first base class" <<
endl; cout << "Inside child class" <<
} endl;
~Parent1() }
{ ~Child()
cout<<"Destructor of Parent1 called"<< {
endl;
}}; cout<<"Destructor of child
class Parent2 called"<< endl;
{
public: }
Parent2() };
{
cout << "Inside second base class" << // main function
endl; int main() {
}
// creating object of class Child
~Parent2() Child obj1;
{
return 0;
cout<<"Destructor of Parent2 called"<< }
endl;
} };
Constructor and Destructor in Inheritance: Ex.
Inside first base class
Inside second base class
Inside child class
Destructor of child called
Destructor of Parent2 called
Destructor of Parent1 called

You might also like