Chapter 10 - Notes
Inheritance
Inheritance is a solution to a problem where components being managed have similar attributes, differing only minutely in details and behaviour.
It allows us to abstract the common behaviour into a common base class, and have each component inherit from this base class.
Examples
Base Class
Example Derived Classes
Fish
Goldfish, Carp, Tuna
Mammal
Human, Elephant, Lion, Platypus
Bird
Crow, Parrot, Ostrich
Shape
Circle, Polygon
Polygon
Triangle, Octagon
The derived classes, in almost all instances, should be more specific than that of its base class.
Syntax
class Base
{
// implementation of Base
};
class Derived: <access-specifier> Base
{
// implementation of Derived
}The access-specifier is either public (most common), private, or protected.
Using the `protected` access specifier
The protected access modifier allows one to define member variables and functions in a base class that are only accessible within the scope of the derived class.
Base Class Initialisation
If an overloaded constructor of the base class is defined, it can be invoked using the initialisation list syntax.
class Base {
public:
Base(int someNumber) {
// Use someNumber
}
}
class Derived: public Base {
public:
Derived(): Base(25) // Instantiate Base with argument 25
{
// Derived class constructor code
}
}This is useful for ensuring any required member variables are provided.
Overriding Base Class Methods
If a derived class implements a function with the same prototype to that of the base class that it inherits from, it effectively overrides the base class method.
class Fish {
public:
void speak() {
std::cout << "blup blup" << std::endl;
}
}
class Carp {
public:
void speak() {
std::cout << "swish swoosh" << std::endl;
}
}If .speak() was invoked using an instance of Carp, then the Carp::speak() method is invoked, overriding the Fish::speak() method.
Invoking Overridden Base Class Methods
Through an instance of a derived class
If you want to be able to invoke the Fish::speak() method via an instance of Carp, you need to use the scope resolution operator:
Carp carp;
carp.Fish::speak();Within the scope of a derived class
If a derived class needs to re-use and invoke the implementation of an overridden method, you can also use the scope resolution operator:
class Carp: public Fish {
public:
Carp(): Fish() {}
void speak() {
Fish::speak();
std::cout << "swish swoosh" << std::endl;
}
}This would result in "blup blup" followed by "swish swoosh".
Hiding a Base Class' Methods
Overriding also allows derived classes to "hide" overloaded versions of a function in its base class.
class Fish {
public:
void Swim();
void Swim(bool quickly); // Overloaded version
}
class Tuna: public Fish {
public:
void Swim();
}
int main() {
Tuna tuna;
Tuna.Swim(false); // Compileation error: Tuna::Swim() hides Fish::Swim(bool)
}If you want to be able to invoke Fish::Swim(bool), the following options are available:
Use the scope resolution operator
tuna.Fish::Swim(false);Use keyword
usinginTunato unhide theFish::Swim(bool)function:
class Tuna: public Fish {
public:
using Fish::Swim; // unhide all Fish::Swim methods
void Swim();
}(Preferred) Override all overloaded variants of
Fish::SwiminTuna
class Tuna: public Fish {
public:
void Swim();
void Swim(bool quickly); // calling tuna.Swim(false) invokes Tuna::Swim(bool)
}Order of Construction
Base class objects are instantiated before the derived class. This ensures that any member attributes of the base class are ready to be used in the constructor of the derived class.
Order of Destruction
The order of destruction is opposite to that of construction. When an instance of a derived class foes out of scope, the destructor of the derived class is first called, then the base class.
Inheritance Types
Private Inheritance
class Base {
// ...
}
class Derived: private Base { // private inheritance
// ...
}Private inheritance of a base class means that all public members and attributes of the base class are private to anyone with an instance of the derived class.
Public members and methods of Base can be consumed within the scope of Derived, but not by anyone else in possession of an instance of Derived.
Private inheritance does not imply an "is-a" relationship between Derived and Base, since none of the behaviours of Base can be invoked/accessed with an instance of Derived.
Private inheritance implies a "has-a" relationship, as it can invoke behaviours of Base within its scope.
Protected Inheritance
class Base {
// ...
}
class Derived: protected Base { // private inheritance
// ...
}Protected inheritance is similar to private inheritance in the following ways:
It also expresses a has-a relationship.
It also lets the derived class access all public and protected members of Base.
Those outside the inheritance hierarchy with an instance of
Derivedcannot access public members ofBase
The difference is when the Derived class is further derived from:
class Derived2: protected Derived {
// Can access public & protected members of Base
}Protected inheritance allows subclasses of the subclass to access public and protected members of the Base class. This is nor possible with private inheritance.
Instance Slicing
Slicing occurs when an object of a derived class is copied into an object of a base class.
Derived derived;
Base base = derived; // Valid, will compile and run. What occurs is that the compiler copies only data of the Base part of Derived, in other words, not the complete object. The information contained in the Derived instance is lost in this process. This is known as slicing or narrowing.
To avoid this, don't pass parameters by value, pass them instead as pointers to the base class.
Multiple Inheritance
A derived class may inherit more than one base class.
class A {
void foo();
}
class B {
void bar();
}
class Derived: public A, public B {
// ...
}
int main() {
Derived derived;
derived.foo(); // Yes, from A
derived.bar(); // Yes, from B
}Preventing Inheritance
A class declaration suffixed with final ensures that the class cannot be inherited from.
class Foo {
// ...
}
class Bar final: public Foo {
// ...
}
class Baz: public Bar { // Compile error: Bar is `final` class
// ...
}Last updated
Was this helpful?