7.1
Introduction:
Inheritance is a process of creating new classes,
called derived classes from the existing class or base class. The derived class
inherits all the capabilities of the base class but can add members and
refinements of its own. The base class is unchanged by this process.
Inheritance has important advantages. Most importantly, it permits code
reusability. Reusability is yet another important feature of OOP. C++ strongly
supports the concept of reusability. The C++ classes can be reused in several
ways. Once a class has been written and tested, it can be adapted by other
programmers to suit their requirements. Creating new classes, reusing the
properties of the existing ones, basically does this. The mechanism of deriving
a new class from an old one is called inheritance
(or derivation). The old class is
referred to as the base class and the
new one is called the derived class.
The derived class inherits some or all of
the traits from the base class. A class can also inherit properties from more
than one class or from more than one level. A derived class with only one base
class is called single inheritance and
one with several base classes is called multiple
inheritance. On the other hand, more than one class may inherit the traits
of one class. This process is known as hierarchical
inheritance. The mechanism of deriving a class from another 'derived class'
is known as multilevel inheritance. Figure
shows various forms of inheritance that could be used for writing extensible
programs. The direction of arrow indicates the direction of inheritance.
a) Single inheritance: b)
Multilevel inheritance
c) Multiple inheritance e)
Hierarchical inheritance
![]() |
|||
![]() |
|||
7.2
Defining Derived Classes:
A derived class is defined by specifying
its relationship with the base class in addition to its own details.
The general form of defining a derived
class is:
class derived-class-name : visibility-mode base-class-name
{
………… //
…………
II members of derived class
…………II
};
The colon indicates that the derived-class-name is derived from the base-class-name. The visibility mode is
optional and, if present, may be either private
or public. The default visibility-mode is private. Visibility mode specifies whether the features of the base
class are privately derived or publicly derived.
Examples:
class ABC: private XVZ //private derivation
{
members of ABC
};
class ABC : public XVZ //public derivation 3
{
members of ABC
};
class ABC : XVZ //private derivation by
default
{
members of ABC
};
When a derived class privately inherits a
base class, 'public members' of the base class become 'private members' of the
derived class and therefore the public members of the base class can only be
accessed by the member functions of the derived class. They are inaccessible to
the objects of the derived class. Remember, a public member of a class can be
accessed by its own objects using the dot operator. The result is that no
member of the base class is accessible to the objects of the derived class.
On the other hand, when the base class is publicly inherited, 'public members' of
the base class become 'public members' of the derived class and therefore they
are accessible to the objects of the derived class. In both the cases, the private members are not inherited and
therefore, the private members of a base class will never become the members of
its derived class.
In inheritance, some of the base class data
elements and member functions are 'inherited' into the derived class. We can
add our own data and member functions and thus extend the functionality of the
base class. Inheritance, when used to modify and extend the capabilities of the
existing classes, becomes a very powerful tool for incremental program
development.
7.3
Single Inheritance:
A derived class with only one base class is
called single inheritance. Consider
the program below:
# include <jostream.h>
class Counter II base class
{
protected: //
NOTE: not private
unsigned int count; // count
public:
Counter( ) { count = 0; } //constructor, no args
Counter(int c) { count = c; } // constructor, one arg
int get_count( ) { return
count; } // return count
Counter operator ++ ( ) // increment count
{
count++; //
increment count, return
return Counter(count); //an unnamed temporary
object
} //
initialized to this count
};
class CountDn : public Counter // derived class
{
public:
Counter operator --( ) // decrement count
{
count--; //
decrement count, return
return Counter(count); // an unnamed temporary
object
} //
initialized to this count
};
void main( )
{
CountDn cl; // c1 of class
CountDn
cout << "\ncl=" <<
c1.get-count(); //
display c1
cl++;
cl++;
cl++;
cout << "\ncl=" <<
cl.get-count( ); //
display it
c1--;
c1--;
cout << .'\nc1=" <<
c1.get-count( ); // display
it
}
7.4
Accessing Base Class Members:
An important topic in inheritance is
knowing when objects of the derived class can use a member function in the base
class. This is called accessibility.
Substituting
Base Class Constructors: In
the main ( ) part of the above program:
CountDn c1;
This causes c1 to be created as an object of class countDn and initialized to 0. There is no constructor in the CountDn class specifier, if you don't
specify a constructor, the derived class will use an appropriate constructor
from the base class. This flexibility on the part of the compiler using one
function because another isn't available is feature of inheritance. Generally
the substitution is what you want, but sometimes it can be error also.
Substituting Base Class Member Functions: The object c1 of the countDn class also uses the operator++( ) and get-count ( ) functions from the counter class. The first statement is used to increment c1:
c1++;
and the second statement is used to display
the count in c1:
cout << "\nt1="
<< t1.get_count( );
Again the compiler, not finding these
functions in the class of which c1 is a member, uses member functions from the
base class. The ++ operator, the constructors, and the get_count( ) function in
the counter class, and the - - operator in the countDn class, all work with
objects of type countDn.
7.5
Making A Private Member Inheritable (protected):
C++ provides a third visibility modifier,
protected, which serves a limited purpose in inheritance. A member declared as
protected is accessible by the member functions within its class and any class immediately derived from it. It cannot be accessed by the functions
outside these two classes. A class can now use all the three visibility modes
as illustrated below.
class alpha {
private: //optional
………. //visible to member
functions
………. //within its class
protected :
………. //visible to member functions
………. //of its own and derived class
public :
………. //visible to ail functions
………. //in the program
};
When a protected
member is inherited in public mode,
it becomes protected in the derived
class too, and therefore is accessible by the member functions of the derived
class. It is also ready for further inheritance. A protected member, inherited in the private mode derivation, becomes private in the derived class. Although it is available to the
member functions of the derived class, it is not available for further inheritance (since private members cannot
be inherited). Table summarizes how the visibility of members undergo
modifications when they are inherited.
Table: Visibility of inherited members
Base class Visibility
|
Derived class visibility
|
||
Public derivation
|
Private derivation
|
||
Private
|
Not inherited
|
Not inherited
|
|
Protected
|
Protected
|
Private
|
|
Pubic
|
Pubic
|
Private
|
|
The keywords private, protected, and public
may appear in any order and in any number of times in the declaration of a
class.
For example,
class beta
{
protected :
……….
public :
……….
private:
………..
public :
……….
};
is a valid class definition.
However, the normal practice is to use them
as follows:
class beta
{ ………. //private by default
……….
protected :
……….
public :
……….
}
The following table summarizes the
situation in a different way.
Access
Specifier
|
Accessible
from
Own
class
|
Accessible
from
Derived
class
|
Accessible
from
Objects
outside class
|
public
|
yes
|
yes
|
Yes
|
Protected
|
yes
|
yes
|
No
|
Private
|
yes
|
No
|
No
|
7.6
Derived Class Constructors:
The compiler will substitute a no-argument
constructor from the base class, when there is no constructor for the derived
class, but it draws the line at more complex constructors. To make such a definition
work we must write a new set of constructors for the derived class, consider
the program below.
#
include <iostream.h>
class Counter
{
protected: //
NOTE: not private unsigned
int count; //
count
public:
Counter( ) { count = 0; } // constructor, no args
Counter(int c) { count = c; } // constructor, one arg
int get_Count( ) { return
count.; } // return count
Counter operator ++ ( ) //increment count
{
count++; //
increment count, return
return counter(Count); // an unnamed temporary
object
} //
initialized to this count
};
class countDn : public counter
{
public:
CountDn( ) : Counter( ) // constructor, no args
{ }
CountDn(int c) : Counter(c) // constructor 1 arg
{ }
CountDn operator --( ) // decrement count
{
count--; //
decrement count, return
return countDn(Count); // an unnamed temporary object
} // initialized to this
count
};
void main( )
{
CountDn c1;
CountDn c2(100);
cout << "\nc1=" <<
c1.get-Count( );
cout << " \nc2=" <<
c2 .get-Count ( ) ;
c1++;
c1++;
c1++;
cout << "\nc1=" <<
c1.get-Count( );
c2--; c2--;
cout << "\nc2=" <<
c2.get-Count( );
CountDn c3 = c2--;
cout << "\ric3=" <<
c3.get-Count( );
}
This program uses two new constructors in
the countDn class. Here is the one
argument constructor:
CountDn( ) : Counter( )
{ }
This
constructor has an unfamiliar feature: the colon followed by a function name.
This construction causes the CountDn ( )
Constructor to call the counter( ) constructor
in the base class. In main( ) , when
we say
CountDn c1;
the compiler will create an object of type countDn and then call the countDn constructor to initialize it.
This constructor will in turn call the counter
constructor: which carries out the work. The countDn( ) constructor could add additional statements of its own,
but in this case it doesn't need to, So the function body between the braces is
empty. The statement:
CountDn c2(100);
in main(
) uses the one-argument constructor in countDn
.This constructor also calls the
corresponding constructor in the base class:
CountDn(int c) :
Counter(c) ßargument c
is passed to Counter
{ }
This construction causes the argument c to
be passed from countDn ( ) to counter
( ) where it is used to initialize the object. In main( ) , after initializing the c1 and c2 objects, we
increment one and decrement the other and then print the results. The
one-argument Constructor is also used in an assignment statement:
CountDn c3 = c2--;
7.7 Overriding member functions:
You can use member functions in a derived
class that have the same name as those in the base class. You might want to do
this so that calls in your program work the same way for objects of both base
and derived classes.
// Program to demonstrate overloading
functions in base and derived classes
# include <iostream.h>
# include <process.h> //
for exit()
const int MAX = 100; //
maximum size of stack
class Stack
{
protected:
int st[MAX];
public:
Stack( ) //
constructor
{ top = 0; }
void push(int var) //
put number on stack
{ st[++top] = var; }
int pop( ) //
take number off stack
{ return st[top--]; }
};
class Stack2 : public Stack
{
public:
void push(int var) // put
number on stack
{
if(top < MAX) // if stack
not full,
Stack::push(var); // call push( ) in Stack class else
{ cout << "\nError: stack is
full";
exit(1);
}
}
int pop( ) //
take number off stack
{
if(top > 0) //
if stack not empty,
return Stack::pop( ); //
call pop() in Stack class else
{ cout << "\nError: stack is
empty"; exit(1); }
}
};
void main( )
{
Stack2 51;
s1.push(11); // push some values onto
stack s1.push(22);
s1.push(33);
cout << endl << s1.pop( ); // pop some values from stack
cout << endl << s1.pop( );
cout << endL <<
s1.pop( );
cout << endL <<
s1.pop( );
}
7.8 Multilevel Inheritance:
It is not uncommon that a class is derived
from another derived class as shown. The class A serves as a base class for the derived class B that in turn serves as a base class for the derived class C. The class B is known as intermediate
base class since it provides a link for the inheritance between A and C.
The chain ABC is known as inheritance
path.
|
|
Base class A
Grandfather
|
|
Intermediate B Father
|
Derived class C
A derived class with multilevel inheritance
is declared as follows:
class A{ }; //Base class
class B: public A { }; //B derived from A
class C: public B { }; //C derived from B
This process can be extended to any number
of levels. Let us consider a simple example. Assume that the test results of a
batch of students are stored in three different classes. Class student stores
the roll-number, class test stores the marks obtained in two subjects and class
result contains the total marks obtained in the test. The class result can
inherit the details of the marks obtained in the test and. the roll_number of
students through multilevel inheritance. Example:
# include <iostream.h>
class student
{
protected:
int roll_number;
public:
void get-number(int) ;
void put-number(void);
};
void student :: get-number(int a)
{ roll-number = a; }
void student :: put-number()
{ cout << “Roll Number: “ <<
roll-number << “\n"; }
class test: public student //FIRST LEVEL
DERIVATION {
protected:
float subl;
float sub2;
public:
void get-marks(float, float) ;
void put-marks(void) ;
};
void test :: get-marks(float x, float y)
{ subl = x;. sub2 = y; }
void test: : put-marks()
{
cout << "Marks in
SUBl = " << subl << “\n” ;
cout << “Marks in SUB2 = “ << sub2
<< "\n";
}
class result : public test //SECOND LEVEL DERIVATION
{
float total; //private by
default
public:
void display (void) ;
} ;
void result :: display(void)
{
total = subl + sub2;
put_number ( ) ;
put-marks ( ) ;
cout << “Total= “
<< total << "\n”;
}
main( )
{
result student 1; //studentl created
studentl.get-number(lll) ;
studentl.get-marks(75.0, 59.5)
;
studentl.display( ) ;
}
7.9
Multiple Inheritance:
A class can inherit the attributes of two
or more classes. This is known as multiple
inheritance. Multiple inheritance allows us to combine the features of
several existing classes as a starting point for defining new classes. It is
like a child inheriting the physical features of one parent (papa) and the
intelligence of another (mama). The syntax of a derived class with multiple
base classes is as follows:
Class D : visibility B-1, visibility B-2,
{
…………..
………….. (Body of D)
…………..
};
where, visibility
may be either public or private. The base classes are separated by commas.
Example:
# include <iostream.h>
class M
{
protected:
int m;
public:
void get-m(int) ;
} ;
class N
{
protected:
int n;
public:
void qet-n(int) ;
} ;
class P : public M, public N
{
public:
void display(void) ;
} ;
void
M ::get-m(int x)
{ m
= x; }
void N : : get-n(int y)
{ n = y; }
void P ::display(void)
{
cout << "m = "
<< m << "\n";
cout << "n = "
<< n << "\n";
cout << "m*n =
" << m*n << “\n";
}
main( )
{
P p;
p.get-nl(10) ;
p.get-n(20) ;
p.display( ) ;
}
7.10
Hybrid Inheritance:
There could be situations where we need to
apply two or more types of inheritance to design a program. For instance,
consider the case of processing the student results. Assume that we have to
give weightage for sports before finalising the results. The weightage for
sports is stored in a separate class called sports. The new inheritance
relationship between the various classes would be as shown in Fig. Below:
![]() |
|||
|
|
|
# include <iostream.h> ,
class student
{
protected:
int
roll-number;
public:
void get-number(int a)
{ roll-number = a; }
void put-number(void)
{ cout << "Roll No: " << roll number
<< "\n"; }
} ;
class test: public student
{
protected:
float partl, part2;
public:
void get_marks(float x, float
y)
{ partl = x; part2 = y; }
void put_marks(void)
{
cout << "Marks
obtained: " << "\n” << “Fartl = " << partl
<< "\n” << “Fart2 =
“<< part2 <<
"\n" ;
}
};
class sports
{
protected:
float score;
public:
void get-score(float s)
{ score = s; }
void
put-score(void)
{ cout << "Sports wt: " << score
<< "\n\n"; }
} ;
class result: public test, public sports
{
float total;
public:
void display(void) ;
};
void result :: display(void)
{
total = partl + part2 + score;
put_number ( ) ;
put_marks ( ) ;
put_score ( ) ;
cout << "Total
Score: " << total << "\n";
}
main ( )
{
result student_l;
student_l. get_number (1234) ;
student_1.get_nlarks(27.5,
33.0) ;
student_1.get_score(6.0) ;
student_1.display( ) ;
}
7.11 Containership: Classes Within
Classes:
In inheritance, if a class B is derived from a class A, we can say "B is a kind of A". This is because B
has all the characteristics of A,
and in addition some of its own. For
this reason inheritance is sometimes called a "kind of” relationship:
There's another kind of relationship,
called a "has a" relationship, or containership.
In object-oriented programming the "has a" relationship occurs
when one object is contained in another. Here's a case where an object of class
B is contained in a class A:
class A
{
B b; // b is an object of class B
};
class B
{ };
In some situations inheritance and
containership relationships can serve similar purposes. The following program
shows these relationships in a different way:
# include<iostream.h>
const int LEN = 80; // maximum length of names
class student // educational background
{
private:
char school[LEN]; // name of school or university
char degree[LEN]; // highest degree earned
public:
void getedu( )
{
cout << “ Enter name of
school or university: ";
cin >>school;
cout << " Enter
highest degree earned \n";
cout << " (High
school, Bachelor's, Master's, PhD): ";
cin >>degree;
}
void putedu( )
{
cout << "\n School
or university: " << school;
cout << "\n Highest degree
earned: " << degree;
}
};
class employee
{
private:
char name(LEN]; // employee name
unsigned long number; // employee number
public:
void getdata( )
{
cout << "\n Enter
last name: ";
cin >>name;
cout << " Enter
number: ";
cin >>number;
}
void putdata( )
{
cout << "\n Name:
" << name;
cout << "\n Number:
" << number;
}
};
class manager // management
{
private:
char title(LEN]; //
"vice-president" etc.
double dues; // golf club dues
employee emp; // object of class
employee
student stu; // object of class
student
public:
void getdata( )
{
emp,getdata();
cout << " Enter
title: "; cin
>>title;
cout << " Enter golf
club dues: " ; cin >>dues;
stu.getedu( );
}
void putdata( )
{
emp.putdata( );
cout << "\n Title: "
<< title;
cout << "\n Golf club dues:
" << dues;
stu.putedu( );
}
};
class scientist //
scientist
{
private:
int pubs; //
number of publications
employee emp; // object of
class employee
student stu; // object of class student
public:
void getdata( )
{
emp.getdata( );
cout << " Enter number of pubs:
";
cin >>pubs;
stu.getedu( );
}
void putdata()
{
emp.putdata( );
cout << "\n Number of publi
cations: " << pubs;
s u.putedu( );
}
};
class laborer //laborer
{
private:
employee emp; // object of class employee
public:
void getdata( )
{ emp.getdata( ); }
void putdata( )
{ emp.putdata( ); }
};
void main( )
{
manager m1;
scientist s1, s2;
laborer l1;
cout << endl;
cout << "\nEnter data for manager 1"; // get data for
m1.getdata( ); // several employees
cout << "\nEnter
data for scientist 1"; s1.getdata(
);
cout << "\nEnter
data for scientist 2"; s2.getdata(
);
cout << "\nEnter
data for laborer 1"; l1.getdata(
);
cout << "\nData on
manager 1"; m1.putdata( );
cout << "\nData on
scientist 1"; s1.putdata(
);
cout << "\nData on
scientist 2"; s2.putdata(
);
cout << "\nData on
laborer 1"; l1.putdata();
}
Containership is clearly useful with classes that act
like a data type. Then an object of that type can be used in a class in almost
the same way a variable would be. In other situations you will need to examine
the problem carefully and perhaps try different approaches to see what makes
sense. Often the inheritance relationship is simpler to implement and offers a
clearer conceptual framework.
Exercise:
- The class master derives information from both accounts and admin classes, which in turn derive information from the class person. Define all four classes and write a program to create, update and display the information contained in master objects.
- Start with three classes Publication, Book and Tape, add a base class sales hat holds an array of three floats so that it can record the sales of a particular publication. Write a program to use these classes.
- Using the techniques of OOPs design a program that would simulate a simple real world system familiar to you


