Understanding Inheritance in OOP made Easy

In this detailed article, let's explore the concept of Inheritance in Object Oriented Programming with illustrating examples

Introduction

Inheritance is one of the key characteristics of an Object Oriented Programming Language. The other characteristics are Abstraction, Encapsulation and Polymorphism. Any Object Oriented Programming Language must have features that support these characteristics.

What is Inheritance?

Inheritance in an Object Oriented paradigm is similar to the real-world understanding.

Inheritance is when a class or an object can access all the data and functionalities from another class by making itself a “derivative” of the other class.

The class which is the original source of information and functionality is called as a base class or a super class.

The class which marks itself as a derivative of the former is called as a derived class or a sub class.

Inheritance is simply put – a child entity inheriting additional features other than its own, from a parent entity.

What are the different types of Inheritance?

There are four kinds of inheritance based on the way in which a base and derived classes are linked.

Single Inheritance

There is a single base class, which is inherited by a single derived class. The simplest of all kinds, where all the features of the base class are available for use in the derived class.

public class ClassA
{
    protected void DoSomething()
    {
        // something that Class A can only do
    }
}

public class ClassB : ClassA
{
    // DoSomething() is also available here

    protected void DoSomethingElse()
    {
        // something that Class B can only do
    }
}

public class Program
{
    public static void Main(string[] args)
    {
        var classA = new ClassA();
        classA.DoSomething();

        var classB = new ClassB();

        // DoSomething() method
        // of ClassA is also visible
        // for an instance of ClassB
        classB.DoSomething();
        classB.DoSomethingElse();
    }
}

Multilevel Inheritance

Multiple single inheritance levels are chained together to form a series of inheritance. There is a super class Class A, which is inherited by the class Class B, which is again inherited by another class Class C and so on, forming a chain of inheriting classes.

public class ClassA
{
    protected void DoSomething()
    {
        // something that Class A can only do
    }
}

public class ClassB : ClassA
{
    // DoSomething() is also available here

    protected void DoSomethingElse()
    {
        // something that Class B can only do
    }
}

public class ClassC : ClassB
{
    // some functionality
    // + ClassA accessibility
    // + ClassB accessibility via ClassA

    protected void DoNothing()
    {
        // something that ClassC can only do
    }
}

public class Program
{
    public static void Main(string[] args)
    {
        var classA = new ClassA();
        classA.DoSomething();

        var classB = new ClassB();

        // DoSomething() method
        // of ClassA is also visible
        // for an instance of ClassB
        classB.DoSomething();
        classB.DoSomethingElse();

        var classC = new ClassB();

        // DoSomething() method
        // of ClassA
        // DoSomethingElse() method
        // of ClassB
        // is also visible
        // for an instance of ClassC
        classC.DoSomething();
        classC.DoSomethingElse();
        classC.DoNothing();
    }
}

Multiple Inheritance

A single class ClassC inherits from multiple base classes (say ClassA, ClassB ..) together, trying to obtain functionalities from all of them together. This is not directly allowed in most of the Object Oriented programming languages, because of its side effect which can impact the compilation.

public class ClassA
{
    protected void DoSomething()
    {
        // something that Class A can only do
    }
}

public class ClassB
{
    protected void DoSomethingElse()
    {
        // something that Class B can only do
    }
}

// Doesn't work
// a Compile-time Error is thrown
public class ClassC : ClassA, ClassB
{
    // some functionality
    // + ClassA accessibility
    // + ClassB accessibility via ClassA

    protected void DoNothing()
    {
        // something that ClassC can only do
    }
}

public class Program
{
    public static void Main(string[] args)
    {
        var classA = new ClassA();
        classA.DoSomething();

        var classB = new ClassB();

        classB.DoSomethingElse();

        var classC = new ClassB();

        /* DOES NOT WORK THIS WAY */
        classC.DoSomething();
        classC.DoSomethingElse();
        classC.DoNothing();
    }
}

Instead multiple inheritance can be achieved by extending from a single base class and multiple interfaces.

public class ClassA
{
    protected void DoSomething()
    {
        // something that Class A can only do
    }
}

public interface IClassB
{
    // declares a method
    // any class that implements
    // IClassB must provide a definition
    void DoSomethingElse();
}

public class ClassC : ClassA, IClassB
{
    // some functionality
    // + ClassA accessibility
    // + ClassB accessibility via ClassA

    protected void DoNothing()
    {
        // something that ClassC can only do
    }

    public void DoSomethingElse()
    {
        // something that IClassB wants you to do
    }
}

A class can extend only one base class but can implement multiple interfaces.

Hierarchical Inheritance

In this type, there is a single base class ClassA which is extended by multiple child classes ClassB, ClassC, .. forming a tree sort of schema.

public class ClassA
{
    protected void DoSomething()
    {
        // something that Class A can only do
    }
}

public class ClassB : ClassA
{
    protected void DoSomethingElse()
    {
        // something that Class B can only do
    }
}

public class ClassC : ClassA
{
    // some functionality
    // + ClassA accessibility

    protected void DoNothing()
    {
        // something that ClassC can only do
    }
}

public class Program
{
    public static void Main(string[] args)
    {
        var classA = new ClassA();
        classA.DoSomething();

        var classB = new ClassB();
        classB.DoSomething();
        classB.DoSomethingElse();

        var classC = new ClassB();
        classC.DoSomething();
        classC.DoNothing();
    }
}

Hybrid Inheritance

Hybrid Inheritance is a sort of combination of any of the above types of inheritance together.

How to access Parent Class members in Inheritance

In Encapsulation, we saw how access modifiers can alter access to an element of a class from outside access.

The inherited scope describes how an element can be accessed from any of the three possible means of invocation.

Public and Protected members of a base class can be directly accessed within a derived class without any issues, whereas members marked private and internal cannot be accessed by any derived class.

public class ClassA
{
    protected void DoSomething()
    {
        // something that Class A can only do
    }
}

public class ClassB : ClassA
{
    private void DoSomethingSecretInClassB()
    {
        // something that is internal to ClassB
    }

    protected void DoSomethingElse()
    {
        // something that Class B can only do
    }
}

public class ClassC : ClassB
{
    // some functionality
    // + ClassB accessibility
    // + ClassA accessibility

    protected void DoNothing()
    {
        // something that ClassC can only do
    }
}

public class Program
{
    public static void Main(string[] args)
    {
        var classA = new ClassA();
        classA.DoSomething();

        var classB = new ClassB();
        classB.DoSomething();
        classB.DoSomethingElse();

        var classC = new ClassB();
        classC.DoSomething();

        // classC.DoSomethingElse() is not even visible
        // because of private access specifier

        classC.DoSomethingElse();
        classC.DoNothing();
    }
}

The “is-a” relationship

When two classes are related to one another by means of inheritance, there can be a slight difference in how these can be instantiated. For example, assume there is a base class Animal and a derived class Tiger.

public class Animal
{
    protected void MakeANoise()
    {
        Console.WriteLine("Grrrrr!");
    }
}

public class Tiger
{
    protected void Roar()
    {
        Console.WriteLine("I'm a Tiger! Roaarrr!");
    }
}

public class Program
{
    public static void Main(string[] args)
    {
        Animal a = new Animal();
        a.MakeANoise();

        Tiger t = new Tiger();
        t.Roar();

        Animal another = new Tiger();
        another.MakeANoise();
        // another.Roar() isn't visible 
        // because the reference is of type Animal, not Tiger
    }
}

In the above statement, we’re creating an instance of type Tiger (the right hand side) and assigning it to a type Animal (the left side). This is completely valid syntactically in object oriented programming because a subclass “is-a” base class.

What is method Overriding in Inheritance?

Method Overriding is a scenario in which a base class and a derived class have the same method signature and different implementations.

These methods share the same name and same signature but with different implementations depending on their types.

The base method is overrided by the same method composition of its derived type when being called at the client.

public class Animal
{
    protected void MakeANoise()
    {
        Console.WriteLine("Grrrrr!");
    }
}

public class Tiger : Animal
{
    protected void MakeANoise()
    {
        Console.WriteLine("I'm a Tiger! Roaarrr!");
    }
}

public class Program
{
    public static void Main(string[] args)
    {
        Animal a = new Animal();
        a.MakeANoise();

        Tiger t = new Tiger();
        t.MakeANoise();
    }
}

// Output
warning CS0108: 'Tiger.MakeANoise()' hides inherited member 'Animal.MakeANoise()'. Use the new keyword if hiding was intended.

To vary which implementation of a method is to be called among inheritance we can use virtual, override, abstract and new keywords.

Conclusion

I hope this article gave you a clear understanding of what is meant by Inheritance in OOP, the types of Inheritance and why it is useful. We have also looked at how we implement Inheritance in OOP and its limitations.

Features and some Limitations of Inheritance

  1. Inheritance is one of the characteristic features of Object Oriented Programming languages.
  2. Inheritance provides extension of a base functionality of a parent class by its child classes or derived classes.
  3. Although inheritance improves code-reuse and extension, overusing it might add to code complexity and make code less readable.
  4. There are different types of inheritance possible:
    • Simple – One parent, One Child
    • Multi-level – a chain of parent-child classes
    • Tree – One parent, multiple child
    • Multiple – multiple parents, one child
  5. C# does not support multiple inheritance but other three inheritances
  6. In C# you can extend only one concrete parent class, while you can implement more than one interface
  7. Inheritance can provide access to the base class elements in the derived class but is limited to public and protected only
  8. When two classes are linked together as a base class and a derived class, a derived class “is-a” base class

Is Inheritance possible for a static class?

The answer is No. The following are the characteristics of a Static class which makes it ineligible for Inheritance.

  1. Static classes can contain only static members.
  2. Are sealed by default – no other classes can extend a static class.
  3. Can’t be instantiated. Cannot contain an instance constructor or a constructor with parameters.
  4. Creating a static class is similar to creating a class with all static members and a private constructor.
  5. Static classes can’t extend from any other class other than Object.
  6. Static classes can contain a static constructor, which is called before the first member of the static member is called.

Buy Me A Coffee

Found this article helpful? Please consider supporting!

Ram
Ram

I'm a full-stack developer and a software enthusiast who likes to play around with cloud and tech stack out of curiosity. You can connect with me on Medium, Twitter or LinkedIn.

Leave a Reply

Your email address will not be published. Required fields are marked *