Inheritance lets you create new classes by adding things to an existing class. You don't change the old one. You don't have to recompile it. You tell the compiler that your new class is just like an older with some additional attributes(data) and operations(functions).
The Problem
Suppose you are a programmer for a college. They have already have
designed, written, coded and tested a class called Person. An
object in this class holds personal information about somebody like
their Social Security Number, their names, their address, their gender,
date_of_birth(dob), phone number,
and so on. A Person also has functions (know-how) that can
print the information in a standard format, display it, construct a
new person from given data, destroy the records of a person, increase
the age, change the name, handle a change of address, ... and so on.
Your task is to create a very similar class called Student. A student object is a special kind of Person - one that can take courses, can add and drop sections, has a GPA, and so on. Just like a Person a student need to be able to print itself, display itself, construct it self, destroy all its data, increase its age, change a name, change an address, ... plus doing student things like adding, dropping, passing, failing, and such.
In the old days you had to copy the Person class file and edit it to make the Student class. But this will take time and may introduce errors.
Worse, when we had to change froma 2 digit year to a 4 digit year we had to do a duplicate change in to Student.
When we had to change from SSNs to Student Ids we had to change the definition of Student as well.
Now the college also needs a Faculty class, a Student_assistant class, and a Staff class. These are all different kinds of People! So, every time you change the code for Person, you have to edit the code for five other classes as well.
A Solution form the 1970s
It would be better to define the class Student so that it explicitly
had a field for the personal data and #include the file containing the
Person classes code (Person.h), and write a Student.h file
like this:
#include "Person.h"
class Student {
public:
//add, drop, pass, fail, ....
private:
Person person;
float GPA;
//data structures pointing to sections
};//class StudentIn file Student.cpp would go the code for the implementations of functions specific to Student:
Student::add()and so on.
But this does not give Student the public functions that a Person has. Because the person inside Student is a private Person we can not do anything "Personal".
So you have to include in the public part of Student a list of functions that duplicates the functions in Person.
#include "Person.h"
class Student {
public:
//add, drop, pass, fail, ....
//duplicated code from Person.h
private:
Person person;
float GPA;
//data structures pointing to sections
};//class StudentThe code in "Student.cpp" must define functions like
void Student::add(....){.....}
and also a complete set of functions like this:
void Student::display(){ person.display(); ...}
void Student::inc_age(int years){person.inc_age(years);...}
etc. calling those in Person.
(DRY): Duplicated code breaks the vital DRY principle of programming:
Don't Repeat Yourself!
Similarly for all other "People-like" classes: Faculty, Staff, etc. you (and other people in your team) would have to write code for every function in People. And they would all be rather boring and similar.
If Person is changed by adding, deleting or modifying any functions then so must all the People_like classes. This is not a good use of your time!
Solution by Inheritance
The modern solution is to use "inheritance".
It makes sure that a Student has a complete
up-to-date Person as part of the student! More, inheritance automatically gives
the functions of Person to a Student! So if Student, Faculty, etc all
"inherit from" Person, then when we change Person, its as if they had
all changed as well. The computer is now working for us.
We say that Student inherits
Person's data and functions. We do it by declaring Student like this:
class Student : public Person { .... };
and then adding the new Student functions.
In file Student.h we'd put something like this:
#include "Person.h"
class Student : public Person {
public:
//add, drop, pass, fail, ....
private:
float GPA;
//data about sections
};//class StudentThe above hides an invisible copy of the Person's data in Student. It implicitly makes Student have all the functions defined for a Person.
In file Student.cpp would go the implementations of the functions like add and so on but not the ones in Person.
Finally we can (if we need to) give Student its own ways of doing its parent's operations. All we do is list them in the Student specification, and implement them in the usual way.
There is no need to declare or define functions that can be done by a Person inside Student. All Students inherit them from their parent: Person. However C++ will let a Student have its own version of a function of Person.
Notice that the data describing a Person is effectively hidden inside the Student. In C++ it the first component in memory before the items added by Student. However these data items are not explicitly mentioned inside Student. There is no Person person item in student... but the data is hidden in there just the same.
Similarly we can derive Faculty from Person. We would derive Staff from Person. We could derive Student_Assistant from Student or from Person or (perhaps) both.
And when the Person class is changed, as long as 'Person.h' doesn't change, we don't even have to recompile the Student, Faculty, etc source files! All the other classes continue to link, load, and run with the new Person. We can change any derived class without fiddling with the base class. We can also derive new specializations without changing either the Person class or any of the Student, Faculty, ... classes.
Simple Example
We are working on a strange program that has Widgets and Wodgets.
A Widget can be zarked.
A Widget is just like a Wodget but it can be be both zarked and
binked. He is how we would declare the classes in C++:
class Widget{ ..... void zark()..... };
class Wodget : public Widget{ ..... bink().....};
Words
We say that Student is derived from Person. Student
inherits properties of a Person. We can also say
the Student extends Person, or Person generalizes Student. We use
an open headed arrow pointing from Student to Person
[ Generalizations in uml1b ]
in UML to indicate inheritance.
We have all these different words because object-oriented
languages are recent developments and their inventors all chose their
own words for their ideas.
| UML | C++ | SmallTalk | Other |
|---|---|---|---|
| Special | derived | subclass | child |
| General | base | superclass | parent |
| Attribute | data member | attribute | data field |
| Operation | function | method | - |
| Signature | header | message | - |
For more on the the different words used by different groups of people see [ objects.glossary.html ] and for some informal definitions see [ Informal Definitions of Terms in objects.glossary ]
Diagrams
The Unified modelling Language (UML)
[ Generalizations in uml1 ]
is designed to make inheritance clearer. For example the diagram below
shows that classes D1 and D2 both inherit operations from BB.
Notice that BB, D1, and D2 have operation f(). In this case an object of class D1 executes D1's version of f(). We say that the D1 f() overrides the f() in BB. Also note that h() is owned by BB and so is inherited by both D1 and D2.
Exercise: What operations belong to which class? Fill in the blanks in this table with the words: Has, No, Inherits BB, or overrides BB:
| Class | f() | g() | h() | |
|---|---|---|---|---|
| BB | Has | No | _____ | |
| D1 | Overrides BB | Has | _____ | |
| D2 | _____ | ____ | Inherits BB |
Similar diagrams are not difficult to do in code and makes complex derivations much easier to see. For example see: [ inheritance.cpp ] , and figure out what this program does? The [ Answer to second exercise ] is below.
The above code is not quite correct. Functions are virtual in the UML and so this [ inhex.cpp ] is some C++ that encodes the above diagram better.
Some Rules of Inheritance
A derived class inherits all public data and functions from its base class, with
the exception of its parent's constructors and destructors. Typically you
have to rethink construction and destruction
for the new class. Further they have
the wrong names! However the base constructors can be called from inside the
derived class and destructors
are called automatically.
A derived class does not get access to its base class's private data and functions. This is a breach of encapsulation. However a base class can declare certain data and functions to be protected. Protected data and functions can be accessed by objects and functions in derived classes - but there are some rather finicky rules about this.
Protected data and functions are declared exactly like private and public data and functions. The lexeme "protected" and colon(":") are placed before a list of declarations in the class.
A derived class can add new functions and data to its base class.
A derived class can also over-load (over-ride or redefine) functions in the base class. The over-ridden functions must be listed in the header and also defined later.
It is not easy for a derived class to remove a function that it's base class defines. All you can do is overload the base function with a function that (1) does nothing, or (2) gives an error message. Wanting to do this may signal a need to rethink whether you have the right base class.
A single base class can give rise to any number of derived classes. Each can add its own functionality and data to the common base class.
A class can be both a parent and a child:
Person
|
Student
|
Student_assistantSo you can describe a whole hierarchy of inter-related components. Object-oriented languages like Java [ java.class.tree.html ] [ java.html ] and Smalltalk [ smalltalk.classes.html ] [ smalltalk.html ] come with large ready made hierarchies of useful classes.
People sell ready-made hierarchies of classes. The commonest of these describe the attributes and behavior of objects on a graphic display: Window, Button, Menu, Icon, and so on. For example when you buy Visual C++ you are getting C++ with such a hierarchy (MSFC) and tools for constructing new classes graphically from old ones. These are not free and only work on one kind of computer.
Notice the new use of the reserved word: "public" and the position of the colon before the "public".
class Student_intern: public Student { ... };
Syntax Exercise
Which of the following correctly derives class Lion from class Animal
Net
. . . . . . . . . ( end of section Syntax) <<Contents | End>>
When to use inheritance
Mathematically inheritance is rather like the subset relationship from set
theory. Students are a subset of Human, and so Student behavior is
based on Human behavior.
Before you derive a new class D from a base class B ask yourself the
following questions:
Net
Designing Class Hierarchies
There has been a lot written about this. There have been several
projects that have had problems later on because they skimped
on the thinking involved. There is lots of reading and practice
needed before you can claim to be good at this kind of design.
[ Object-Oriented in methods ]
Luckily human beings seem to be habitual makers of
classification hierarchies
In a complex project you must however make time early on to plan
a stable hierarchy. This takes some thought, experimentation, and
discussion.
A well thought-out
hierarchy can make a set of programs easy to develop. This
called the architecture of the code. A badly thought
out hierarchy can make modifying a program harder.
Multiple Inheritance
In C++ we can derive a new class from any number of parents. For example,
if Student is the kind of Person who studies and Teacher is the kind of
Person who teaches a class, and Employee is the kind of Person who is
paid, then we might derive Student_assistant from Student, Teacher, and
Employee. A student Intern might be derived from Student and Employee.
class Student_assistant : public Student, public Teacher, public Employee {
//constructors and destructors
//etc
}//class Student_assistantFaculty might be derived from Employee and Teacher, but not from Student.
This is called multiple inheritance. It is a controversial idea. There are some odd difficulties with it. For example, If you derive a class D from two base classes: B1 and B2
class B1 {...};
class B2 {...};
class D: public B1, public B2 {...};
and both B1 and B2 have a public function f, but D
does not, then you can not tell if d.f() is really
d.B1::f()or
d.B2::f()This may be spotted by the compiler... but even if it is not, it is something to be avoided.
Worse, if B1 and B2 are derived from a common third base class A:
class A {...};
class B1 : public A {...};
class B2 : public A {...};
class D: public B1, public B2 {...};
then it is not clear how
many As are in a D.
Does each B have an A that is hidden in a D? Or is only
one A hidden in D? In C++ the default is for D to have an A associated
with B1 and another distinct A associated with B2. However, it is
possible for B1 and B2 to be defined so that they will share a single A
whenever they are both base classes for a derived class like D:
class A {...};
class B1 : virtual public A {...};
class B2 : virtual public A {...};
class D: public B1, public B2 {...};
For the moment assume that multiple inheritance is to be avoided unless
you are sure these problem do not occur.
Joke
It said that if you shoot your foot in C++ then the other foot also
gets shot because its part of a virtual leg.
. . . . . . . . . ( end of section Inheritance) <<Contents | End>>
Next
See Polymorphism
[ polymorphism.html ]
and Abstraction
[ abstraction.html ]
Answer to exercise
They are all wrong! Here is the correct syntax for deriving
class Lion from class Animal:
class Lion : public Animal { ... };
(Don't forget the ';' at the end of the class!)
BBh BBf
BBh D1f D1g
BBh D2f D2g
| Class | f() | g() | h() | |
|---|---|---|---|---|
| BB | Has | No | Has | |
| D1 | Overrides BB | Has | Inherits BB | |
| D2 | Overrides BB | Has | Inherits BB |