Inheritance in OOP

Submitted by sylvia.wong@up… on Wed, 02/02/2022 - 00:34
Sub Topics

What is Inheritance in OOP?

We may inherit mannerisms/behaviours, physical features and habits from our parents. Someone might tell you that you look exactly like your grandfather, or that your mannerisms are similar to your mothers. It’s the same in programming. Inheritance is simply taking properties, and methods from another class. Whenever we want to extend the functionality of an existing class, we use inheritance.

  • Deriving a new class from an existing class is inheritance.
  • The existing class is the base class.
  • The new class is the derived class
  • Every member (property and function) of the existing class will be inherited into the derived class except private members.

Inheritance is a way of creating a new class by starting with an existing class and adding new members. The new class can replace or extend the functionality of the existing class. Inheritance models the 'is-a' relationship between classes. It is just like saying "A is a B type of thing". For example, Apple is a Fruit, Car is a Vehicle etc. Inheritance is unidirectional. For example, House is a Building. But Building is not a House.

A diagram depicting the cocept of inheritance

A

Arrow means derived from

B

Defined in derived class

C

Defined in base class but accessible from dervied class

Note: You may read different terminology when reading about inheritance. Some programmers like to use parent and child class terminology.

  • Base class – parent (or superclass) – the class being inherited from
  • Derived class – child (or subclass) – that inherits from another class

Inheritance is useful for code reusability. You can reuse attributes and methods of an existing class when you create a new class.

The Cherno describes it as a way of ensuring you don’t have to have the same code repeated multiple times. By creating a base class, subclasses can be created to access functions from that base class. He says that in OOP there’s a huge paradigm and inheritance between classes is one of the fundamentals and one of the most powerful features that can be leveraged. Watch his video to learn more.

To inherit from a class use the : (semi colon) symbol.

Inheritance Syntax and Notation

A diagram depicting Inheritance Syntax and Notation

Inheritance of Members

 

Class Access

A derived class can access all the non-private members of its base class. This means base-class members that should not be accessible to the member functions of derived classes should be declared private in the base class.

A derived class inherits all base class methods with the following exceptions:

  1. Constructors, destructors and copy constructors of the base class.
  2. Overloaded operators of the base class.
  3. The friend functions of the base class.

Base Class Access Specification

Base class access specification determines how private, protected, and public members of base class can be accessed by derived classes

C++ supports three types of inheritance modes, also called base class access modes:

  1. public inheritance - When deriving a class from a public base class, public members of the base class become public members of the derived class and protected members of the base class become protected members of the derived class. A base class's private members are never accessible directly from a derived class, but can be accessed through calls to the public and protected members of the base class.
    Syntax: class Child: public Parent {};
  2. protected inheritance - When deriving from a protected base class, public and protected members of the base class become protected members of the derived class.
    Syntax: class Child: protected Parent {};
  3. private inheritance - When deriving from a private base class, public and protected members of the base class become private members of the derived class.
    Syntax: class Child: private Parent {};

Base Class Access vs Member Access specification:

Base class access is not the same as member access specification:

A diagram identifying Base Class Access vs Member Access

  • A - Base class access: determine access for inherited members
  • B - Member access specification: determine access for members defined in the class
Base class access specifiers:
  1. public – object of derived class can be treated as object of base class (not vice- versa)
  2. protected – more restrictive than public but allows derived classes to know some of the details of parents
  3. private – prevents objects of derived class from being treated as objects of base class.
How are base class members inherited?
Type of inheritance (base class access specifier) Private members Protected members Public members
private Inaccessible Become private in derived class Become private
protected Inaccessible Stay protected Become protected
public Inaccessible Stay protected Stay public

A diagram depicting base class specifiers

 

Member Access Specification:

Specified using the keywords private, protected and public.

 
Types of access Meaning
private Class members declared as private can be used be member functions and friends (classes or funcions) of the class.
protected Class members declared as protected can be used by member functions and friends (classes or functions) of the class. Additionally, they can be used by classes derived from the class.
public Class members declared as public can be used by any function.

When a subclass takes functions from two base classes it is known as multiple inheritance. Information is taken from more than one base class to get an outcome in the new derived class. Codearchery uses the example of a child getting pocket money from both his mother and father. But there is a lot more to inheritance that is covered here, so these skilfully created videos are worth watching to get an all rounded understanding of how inheritance can be utilised.

  1. Single Inheritance in C++ - 39
  2. Inheritance in C++ - 38
  3. Access Specifiers in inheritance (must watch) - 40
  4. Multiple InheMultilevel Inheritance in C++ - 41
  5. Multiple Inheritance in C++ - 42
  6. Hierarchical Inheritance in C++ - 43
  7. Hybrid Inheritance in C++ - 44
A bunch of codes displayed on a screen

Photo by Chris Ried on Unsplash

Inheriting Multiple Base classes:

It is possible for a derived class to inherit two or more base classes. Look at the following as an example of how derived inherits classes Base1 and Base2. To inherit more than one base, use a comma separator list. Also be sure to use an access specifier for each base inherited.

 

Output:

10
20

If you haven’t already – watch the Multilevel Inheritance in C++ video from the list above.

© Learning works

Practice 1

Write a simple program to demonstrate public inheritance.

This example gives an explanation of how it works:

Output:

1 2
3

To explain the above program: the member functions that are declared under public void set() and void show() are available as public in derived class derived. This means they can be accessed with the derived type object obj outside the classes because they are public.

Practice 2

The following program was written to demonstrate private inheritance. Explain what the output be and why.

Here’s the code:

!@#$

Example explanation:

The derived class derived inherits the base class in private mode. This means the public functions in the base class – void set() and void show() become private in derived class and can’t be accessed outside the derived class in the main() function. Therefore when we try to access these in main() the compiler throws an error.

Practice 3

Write a program to demonstrate what happens to protected data members of a base class when they are inherited by a derived class in public mode.

Remember that by using protected you can create class members that are private to their class yet can be inherited and accessed by a derived class.

Your example might look similar to this:

 

Output:

Compiler Error

Did you get a compiler error? Here’s why:
When protected data members i and j of the base class are inherited in private mode by the derived class derived they become private in the derived class and are accessible within the derived class member function void setk() { k = i * j; }. However the base class public member functions set() and show() when inherited in private mode become private in derived class and are not accessible outside the classes in main() and thus the compiler generates error when a derived class object obj tries to access them.

Practice 4: Now put these all together.

Implement a base class called vehicle:

  • Decide data members and member functions
    Derive two classes from the vehicle base class called car and truck.
  • Decide data members and member functions
    You can read the tutorial on the the tenouk website as your starting point and progress through developing the program to its completion if you want to extend your understanding of class inheritance.

Overriding Base Class Functions

  • Overriding: function in a derived class that has the same name and parameter list as a function in the base class
  • Typically used to replace a function in base class with different actions in derived class
  • Not the same as overloading – with overloading, the parameter lists must be different

Access to Overridden function:

  • When a function is overridden, all objects of derived class use the overriding function.
  • If necessary to access the overridden version of the function, it can be done using the scope resolution operator with the name of the base class and the name of the function: Student::getName()
A cover art that depicts the concept of constructors, destructors and inheritance. A house getting demolished.

Constructors, Destructors, and inheritance

The process of creating and deleting objects in C++ is vital. Each time an instance of a class is created the constructor is called. These are used to initialize the objects of its class. It’s treated as a special member function as its name is the same as the class name. When the associated class is created, these constructors are invoked. Initial values can be passed as arguments to the constructor function when the object is declared in two ways, by calling the constructor explicitly or by calling the constructor implicitly.

Destructors are used to destroy the objects that have been created by the constructor within the program. The destructor doesn’t take argument nor does it return any value and the compiler implicitly invoked up the exit from the program for cleaning up storage that is no longer accessible - for example deletes files or expired links – to clear space in memory.

There are two points that come up relative to constructors and deconstructors when inheritance is involved:

  1. When are base-class and derived class constructors and deconstructors called?
  2. How can parameters be passed to base class constructors?

By inheriting every member of the base class, a derived class object contains a base class object.

The derived class constructor can specify which base class constructor should be used to initialize the base class object.

Order of execution/calling:

When an object of a derived class is created, the base class’s constructor is executed first, followed by the derived class’s constructor. When an object of a derived class is destroyed, its destructor is called first, then that of the base class.

A diagram depicting the order of execution/calling

A - Execute Student constructor, then execute UnderGrad constructor

B - Execute UnderGrad destructor, then execute Student

Constructors are executed in their order of derivation; destructors are executed in reverse order or derivation.

A diagram depicting the order of calling for constructors and deconstructors in iheritance
Order of constructor call Order of destructor call
A {}
Class A constructor
C {}
Class C constructor
B {}
Class B constructor
B {}
Class B constructor
C {}
Class C constructor
C {}
Class C constructor

Prepinsta uses the following code with output to help explain this sequence.

Look at the example code below which shows the sequence using a parent and child class.

Take some time to practice some more of what you have learned.

Practice 5:

Create a project called Base

Create an Animal class (Separate Compilation)

  • Animal.h
  • Animal.cpp

The member function makeNoise() returns string "unknown".

Test your class by instantiating one or more Animal objects inside base.cpp.

Reference: Header files in C++

Example base class:

A UML base class diagram for
 
 
 

Output:

Animal name: myPet
Animal weight: 100
Animal noise: Unknown

Practice 6:

Derived classes with overridden functions - continue with Animal class:

Override makeNoise() to return "Woof!"
digHole() to return "I am digging a hole!".
A UML class diagram for 'animal'
 
 
 

Output:

Animal name: myPet
Animal weight: 100
Animal noise: Unknown
Dog's name: Rover
Dog's weight: 80
Dog's noise: Woof!
Dog's breed: Greyhound
I am digging a hole!

Practice 7: Derived Cat Class

Continue with earlier example:

Override makeNoise() to return "Meow!"
chaseMouse() to return "I am chasing a mouse!".
A UML class diagram for

Solution:

 
 
 

Output:

Animal name: myPet
Animal weight: 100
Animal noise: Unknown
Dog's name: Rover
Dog's weight: 80
Dog's noise: Woof!
Dog's breed: Greyhound
I am digging a hole!
Cat's name: Felix
Cat's weight: 12
Cat's noise: Meow!
I am chasing a mouse!

Passing Arguments to Bass Class Constructor

  • Allows selection between multiple base class constructors
  • Specify arguments to base constructor on derived constructor heading
  • Can also be done with inline constructors
  • Must be done if base class has no default constructor

To pass an argument to a constructor in a base class you use an expanded form of the derived class’s constructor declaration that passes along arguments to one or more base-class constructors.

For example:

 

You will see from the above example that a colon separates the constructor declaration of the derived class from the base classes and the base classes are separated from each other by commas, in the case of multiple base classes. Base1 through baseN are the names of the base classes inherited by the derived class. In general, the constructor of the derived class must declare the parameter(s) that its class requires as well as any required by the base class. Any parameters needed by the base class are passed to it in the bass class’s argument list which is specified after the colon.

And another example here:

 

And more in depth here:

 

Remember from earlier learning that the default constructor of the base class is called ONLY if you don’t specify which one to call.

For example, the default would look something like this:

 

Or you can explicitly call another constructor in the derived class:

 

Overriding base class functions:

  • Overriding: function in a derived class that has the same name and parameter list as a function in the base class
  • Typically used to replace a function in base class with different actions in derived class
  • Not the same as overloading – with overloading, the parameter lists must be different

Access to overridden function:

  • When a function is overridden, all objects of derived class use the overriding function.
  • If necessary to access the overridden version of the function, it can be done using the scope resolution operator (::) with the name of the base class and the name of the function:
 

Read the following article to overriding and access examples, along with explanations of Function Overriding in C++.

Practice 8:

Write a C++ program to demonstrate the sequence in which constructors and deconstructors are invoked from the base class and the derived class.

Your example might look something like this:

 

Output:

Constructing base
Constructing derived
Destructing derived
Destructing base

Practice 9:

Write a program to demonstrate the passing of parameters to base class constructor through derived class.

 

Output:

Constructing base
Constructing derived
4 3
Destructing derived
Destructing base

How did you get on? Are you able to follow your own logic as you build your program? For example, in the above program, the derived constructor takes two parameters x and y i.e. derived (int x, int y): base(y) and passes one to the base class i.e. y. Since show() is under public access specifier and it is available for access outside the classes in the main(). Also the variable x from the base class under protected and can be accessed in the derived class in the show() function also the mode of inheritance of derives class is public.

Hint: It can help your progress greatly when you can explain in your own words, the logical way in which your program works.

Portfolio courses explain how constructors work with Inheritance in C++.

Watch the video:

and access their website, or github to find the source code used in the video.

The ‘this’ pointer:

A hand pointing at the viewer

The member functions of every object have access to a sort of magic pointer named this, which points to the object itself. Thus, any member function can find out the address of the object of which it is a member.

To understand this pointer, it’s important to know how objects look at functions and data members of a class.

  1. Each object gets its own member of the data member
  2. All-access the same function definition in the code segment.

Each object gets its own copy of data members, and all objects share a single copy of member function.

 

When you call a member function, it comes into existence with the value of this set to the address of the object for which it was called. The ‘this pointer can be treated like any other pointer to an object and can be used to access the data in the object it points to.

Accessing member with ‘this

 

The tester() member function accesses the variable alpha as

 

This is the same as referring to alpha directly. This syntax works, but there is no reason for it except to show that this does indeed point to the object.

A more practical use for this is in returning values from member functions and overloaded operators.

Read the article from geeks for geeks to learn more about the ‘this’ pointer in C++.

Aggregation and composition are types of association and only represent a ‘part of’ relationship. You were introduced to UML class diagram relationships in the introduction to OOP in another part of the course so you may want to go back and relook at class relationships.

  • Class aggregation: An object of one class owns an object of another class
  • Class composition: A form of aggregation where the enclosing class controls the lifetime of the objects of the enclosed class
  • Supports the modelling of ‘has-a’ relationship between classes – enclosing class ‘has a(n)’ instance of the enclosed class

Aggregation is called a “has a” relationship. We say a library has a book or an invoice has an item line. It’s a specialised form of association where all objects have their own lifecycle but there is ownership like parent and child. The child object can’t belong to another parent object at the same time – so it is considered to have a ‘has a’ relationship.

In object-oriented programming, aggregation may occur when one object is an attribute of another. Here’s a case where an object of class A is an attribute of class B:

 

A diagram depicting an aggregation flow chart

 

The composition is a part-whole relationship where the parts are contained within the whole. In these parts, some objects are not compulsorily dependent on one object only. They have their independent meaning and existence. For example:

The headlight and engine of a car. The car is the main object, and the headlight and engine are present in a car, but this doesn’t mean that they don’t have their own existence. The headlight can be removed and put into another car.

Aggregation is represented by a hollow diamond attached to a straight line.

A diagram depicting an example of aggregation

Association is a simple structural connection between classes and is a relationship where all objects have their own lifecycle and there is no owner. It is simply some kind of connection between two objects. The relationship may be in one direction or in both directions.

An example is where multiple students can associate with a single teacher and a single student can associate with multiple teachers. There is no ownership between the objects, and both have their own lifecycle, both can create and delete independently.

A diagram depicting course class associates student and department classes

This relationship is represented by:

A diagram depicting course class associates student and department classes

Object composition:

In this type of relationship, the parts of an object are completely dependent on it. Objects would not exist without the object. If we destroy the object, these parts will get destroyed too. Here parent and child objects have coincidental lifetimes. The child doesn’t not have its own lifecycle. If the parents object gets deleted, so does all it’s child objects.

Composition is a stronger form of aggregation. It has all the characteristics of aggregation, plus two more:

  • Typically uses normal member variables.
  • Can use pointer values if the composition class automatically handles allocation/deallocation.
  • Responsible for the creation/destruction of subclasses.
 

This relationship is depicted using a solid diamond attached to a straight line.

A diagram depicting course class associates student and department classes

Aggregation through pointers:

Typically, pointer variables are used to point to an object that lives outside the scope of the aggregate class.

  • A ‘has-a’ relationship can be implemented by owning a pointer to an object
  • Can be used when multiple objects of a class may ‘have’ the same attribute for a member
  • ex: students who may have the same city/state/ zip code
  • Using pointers minimizes data duplication and saves space
  • Aggregation represents the owner/owned relationship between objects.
  • Composition is a form of aggregation in which the lifetime of the owned object is the same as that of the owner object
  • Owned object is usually created as part of the owning object’s constructor, destroyed as part of owning object’s destructor
Member Initialisation Lists

In C++ whenever an object is created, its constructor is called, but also, its parent class is called as are all the constructors for all the objects that belong in the class. By default, the constructors invoked are the default - no-argument constructors. In the definition of a constructor of a class, member initializer lists specify the initializers for direct and virtual bases and non-static data members.

  • Member Initialization lists can be used to simplify the coding of constructors
  • Should keep the entries in the initialization list in the same order as they are declared in the class
  • Allows constructor for enclosing class to pass arguments to the constructor of the enclosed class

You will recall that constructors and destructors interact with class hierarchies. The constructor builds a class object from the bottom up, may use it and then it’s destroyed after. This ordering ensures that the base or a member isn’t used before it’s been initialized or used after it’s been destroyed. Constructors can establish invariants and pick up resources. They do this by initializing class members and base classes.

The members constructors are called before the body of the containing class’s own constructor is executed. The constructors are called in the order in which the members are declared in the class rather than in the order in which the members appear in the initializer list. If the initializers are not in the member declaration order, the compiler should send up a warning.

Think about a class that is used to hold information for a small club or organization.

 

In this example, the Club’s constructor takes the name of the club and its founding date as arguments. Arguments for a member’s constructor are specified in a member initializer list in the definition of the constructor of the containing class.

For example:

 

The member initializer list starts with a colon, and the individual member initializers are separated by commas.

There are two ways to initialize data members of classes. CppNuts outlines both methods in this video, Initializer List in C++ and further in What Are All Those Places Where Initializer List Is Must In C++.

And Portfolio Courses gives a comprehensive explanation of how, when and why to use member initializer lists in C++.

Note: it’s not always necessary to define a constructor for a class when they are relatively simple. Users can initialize objects of a class (or struct) using uniform initialization. Where a class has no constructor, you provide the list elements in the order that the members are declared within the class. If the class does have a constructor, you would provide the elements in order of the parameters. You can learn more about brace initialization (with empty braces) in the Microsoft Visual Studio Library and then continue to initializer_list class outlines.

UML (Unified Modelling Language) Modelling of Class Relationships:

The UML – Unified Modelling Language is a standard visual language for describing and modelling software blueprints. It is specifically for:

  • Visualizing
  • Specifying
  • Constructing
  • Documenting

UML has three main aspects:

  1. Language - This enables a team to communicate about a subject which includes the requirements and the system. Helps with communication and collaboration within a team.
  2. Model – It is a representation of a subject that captures a set of ideas about a subject (these are known as abstractions).
  3. Unified – Brings together the information systems and technology industry’s best practices to apply techniques that allow the successful development of systems.

The UML Class diagram is a graphical representation used to construct and visualize object-oriented programming. It helps describe the structure of a system by showing the classes, attributes, operations or methods and the relationships among the objects.

A class diagram clearly shows the mapping with OOP languages. Object Oriented Concepts Used in UML:

  • Class – A class defines the blue print i.e. structure and functions of an object.
  • Objects – Objects help us to decompose large systems and help us to modularize our system. Modularity helps to divide our system into understandable components so that we can build our system piece by piece. An object is the fundamental unit (building block) of a system which is used to depict an entity.
  • Inheritance – Inheritance is a mechanism by which child classes inherit the properties of their parent classes.
  • Abstraction – Mechanism by which implementation details are hidden from user.
  • Encapsulation – Binding data together and protecting it from the outer world is referred to as encapsulation.
  • Polymorphism – Mechanism by which functions, or entities are able to exist in different forms.

It is generally used for construction purposes and would happen at the beginning of the program planning cycle.

Class diagrams are used for:

  1. describing the static view of the system
  2. showing the collaboration among the elements of the static view
  3. describing the functionalities performed by the system
  4. construction of software applications using OOP’s.

A class may be involved in one or more relationships with other classes and can be one of the following types:

A diagram depicting the kinds of class relationships

Inheritance (or generalization) relationship:

  • A class may be involved in one or more relationships with other classes.
    • The base class name is shown as SuperClass.
    • SubClass1 and SubClass2 are specializations of SuperClass.
  • The figure below shows an example of inheritance hierarchy.
  • SubClass1 and SubClass2 are derived from SuperClass.
  • The relationship is displayed as a solid line with a hollow arrowhead that points from the child element to the parent element.
An example of a child element to the parent element

The figure below shows an inheritance example with two styles.

Although the connectors are drawn differently, they are semantically equivalent

A diagram depicting style of inheritance

A diagram depicting style of inheritance

Association

Associations are relationships between classes in a UML Class Diagram. They are represented by a solid line between classes. Associations are typically named using a verb or verb phrase which reflects the real-world problem domain.

Simple Association:

A structural link between two peer classes.

There is an association between Class1 and Class2

A diagram depicting simple association

The figure below shows an example of simple association. There is an association that connects the <control> class Class1 and <boundary> class Class2. The relationship is displayed as a solid line connecting the two classes.

A diagram depicting simple association

Cardinality

Cardinality is expressed in terms of:

  • one to one
  • one to many
  • many to man

Special type of association:

It represents a "part of" relationship.

Class2 is part of Class1.

Many instances (denoted by the *) of Class2 can be associated with Class1.

Objects of Class1 and Class2 have separate lifetimes.

The figure below shows an example of aggregation. The relationship is displayed as a solid line with a unfilled diamond at the association end, which is connected to the class that represents the aggregate.

A diagram depicting Special type of association

Composition:

A special type of aggregation where parts are destroyed when the whole is destroyed.

Objects of Class2 live and die with Class1.

Class2 cannot stand by itself.

The figure below shows an example of composition. The relationship is displayed as a solid line with a filled diamond at the association end, which is connected to the class that represents the whole or composite.

A diagram depicting Composition.

Dependency:

An object of one class might use an object of another class in the code of a method. If the object is not stored in any field, then this is modelled as a dependency relationship.

A special type of association exists between two classes if changes to the definition of one may cause changes to the other (but not the other way around).

Class1 depends on Class2

The figure below shows an example of dependency. The relationship is displayed as a dashed line with an open arrow.

The figure below shows another example of dependency. The Person class might have a hasRead() method with a Book parameter that returns true if the person has read the book (perhaps by checking some database).

A diagram depicting Dependency

Realisation:

Realization is a relationship between the blueprint class and the object containing its respective implementation level details. This object is said to realize the blueprint class. In other words, you can understand this as the relationship between the interface and the implementing class.

For example, the Owner interface might specify methods for acquiring property and disposing of property. The Person and Corporation classes need to implement these methods, possibly in very different ways.

A diagram depicting the Person and Corporation classes implementations.
Class diagram – order system:
A diagram depicting Class diagram – order system
  1. Attribute
  2. Class
  3. Multiplicity
  4. Association
  5. Aggregation
  6. Role
  7. Operation
  8. Abstract Class
  9. Generalization
A diagram depicting CLASS DIAGRAM – ORDER SYSTEM
  1. Dependency
  2. Note
  3. Abstract Class
  4. Generalization
  5. Composition
  6. Operation
  7. Class
  8. Attribute
  9. Aggregation
  10. Boundary Class
  11. Association
  12. Control Class

Geeks for geeks outlines the rules around UML modelling:

The UML has a number of rules that specify what a well-formed model should look like. A well-formed model is one that is semantically self-consistent and in harmony with all its related models.

The UML has semantic rules for:

  • Names – What you can call things, relationships, and diagrams.
  • Scope – The context that gives specific meaning to a name.
  • Visibility – How those names can be seen and used by others.
  • Integrity – How things properly and consistently relate to one another.
  • Execution – What it means to run or simulate a dynamic model.

Remember that UML is not a programming language but is often described as a visual language that portrays the behaviour and structure of a system. It helps people with modelling, design and analysis.

You can choose to watch Geekific as he explains UML Class and object diagrams in a video. The code snippets can be found at github.

Read the article, UML Class Diagram Explained With C++ samples, from CPP CODE TIPS. There is a step-by-step process to create a UML diagram with code examples.

Module Linking
Main Topic Image
A programmer working on many screens at once.
Is Study Guide?
Off
Is Assessment Consultation?
Off