Inheritance in C#

Inheritance is a fundamental concept in Object-Oriented Programming (OOP) that allows you to define a class that inherits the properties and methods of another class. The class whose properties are inherited is called the base class or parent class, and the class that inherits is called the derived class or child class.

Key Concept: Inheritance promotes code reusability and establishes a relationship between classes, often referred to as an "is-a" relationship. For example, a Dog "is-a" Animal.

Syntax

In C#, you use a colon (:) to indicate inheritance:

public class DerivedClass : BaseClass
{
    // Members of the derived class
}

Example

Let's consider an example where we have a Vehicle base class and a Car derived class:

Base Class: Vehicle

public class Vehicle
{
    public string Brand { get; set; }
    public int Year { get; set; }

    public Vehicle(string brand, int year)
    {
        Brand = brand;
        Year = year;
    }

    public void StartEngine()
    {
        Console.WriteLine("The engine has started.");
    }

    public virtual void Drive()
    {
        Console.WriteLine("Driving the vehicle.");
    }
}

Derived Class: Car

public class Car : Vehicle
{
    public int NumberOfDoors { get; set; }

    // Constructor for Car, calling the base class constructor
    public Car(string brand, int year, int numberOfDoors) : base(brand, year)
    {
        NumberOfDoors = numberOfDoors;
    }

    // Overriding the Drive method from the base class
    public override void Drive()
    {
        Console.WriteLine($"Driving the {Brand} {Year} car with {NumberOfDoors} doors.");
    }

    public void Honk()
    {
        Console.WriteLine("Beep beep!");
    }
}

Key Concepts in Inheritance

1. Base and Derived Classes

2. Constructors and `base` Keyword

When a derived class is instantiated, its constructor is called. If the derived class constructor does not explicitly call a base class constructor, the parameterless constructor of the base class is automatically called. You can explicitly call a base class constructor using the base keyword:

// In the Car constructor:
            public Car(string brand, int year, int numberOfDoors) : base(brand, year)
            {
                // ...
            }

3. Access Modifiers

Inheritance respects access modifiers:

Tip: Use protected for members that should be accessible by derived classes but not by external code.

4. Method Overriding (`virtual` and `override`)

Derived classes can provide their own specific implementation for methods defined in the base class. This is achieved using the virtual keyword in the base class method and the override keyword in the derived class method.

Warning: You cannot override a private method. An override method must have the same signature as the virtual method it is overriding.

5. Method Hiding (`new` Keyword)

If you want a derived class method to have the same name as a base class method but not override it (i.e., create a new, independent method), you can use the new keyword. This is less common than overriding.

public class AnotherCar : Vehicle
{
    // Hides the base class Drive method, does not override it.
    public new void Drive()
    {
        Console.WriteLine("Driving another car.");
    }
}

6. Abstract Classes and Methods

Abstract classes cannot be instantiated. They are designed to be inherited from. Abstract methods do not have an implementation and must be implemented by derived classes.

public abstract class Shape
{
    public abstract double Area(); // Abstract method
}

public class Circle : Shape
{
    public double Radius { get; set; }
    public Circle(double radius) { Radius = radius; }

    public override double Area() // Must implement abstract method
    {
        return Math.PI * Radius * Radius;
    }
}

7. Sealed Classes

You can prevent a class from being inherited by using the sealed keyword. Similarly, you can prevent a method from being overridden by marking it as sealed override.

public sealed class FinalClass { ... }

public class BaseWithSealedMethod
{
    public virtual void DoSomething() { ... }
}

public class DerivedWithSealedMethod : BaseWithSealedMethod
{
    public sealed override void DoSomething() { ... } // Cannot be overridden further
}

Benefits of Inheritance