C# - Inheritance
C# - Inheritance
Section titled “C# - Inheritance”Inheritance is a fundamental pillar of object-oriented programming (OOP). It allows a class to inherit fields and methods from another class, known as the base (or parent) class. The inheriting class is called the derived (or child) class. This mechanism promotes code reusability and helps model real-world ‘is-a’ relationships, leading to more organized and maintainable applications.
By using inheritance, you can create a general base class that defines common functionality and then create more specific derived classes that add or modify that functionality. For example, a Car is a Vehicle, and a Bicycle is a Vehicle. Vehicle would be the base class, while Car and Bicycle would be derived classes.
Base and Derived Classes
Section titled “Base and Derived Classes”In C#, a class can inherit from only one base class (single inheritance), but it can implement multiple interfaces. This design prevents the complexity and ambiguity issues associated with multiple class inheritance, like the ‘Diamond Problem’.
Syntax
Section titled “Syntax”The syntax for creating a derived class is simple. You specify the derived class name, followed by a colon (:) and the name of the base class.
// Base classpublic class BaseClass{ // Members of the base class}
// Derived classpublic class DerivedClass : BaseClass{ // Members of the derived class}Example of Inheritance
Section titled “Example of Inheritance”Let’s modernize the classic Shape and Rectangle example using modern C# properties and constructors. Properties provide a more flexible and safer way to expose data than public fields or simple getter/setter methods.
using System;
namespace InheritanceExample{ // Base class with properties public class Shape { // Auto-implemented properties for width and height public double Width { get; set; } public double Height { get; set; }
public void DisplayDimensions() { Console.WriteLine($"Width: {Width}, Height: {Height}"); } }
// Derived class public class Rectangle : Shape { // Method specific to Rectangle public double GetArea() => Width * Height; }
public class Program { public static void Main(string[] args) { var rect = new Rectangle();
// Set properties inherited from Shape rect.Width = 5.5; rect.Height = 3.0;
rect.DisplayDimensions();
// Call method from the derived class Console.WriteLine($"Area: {rect.GetArea()}"); } }}When the above code is compiled and executed, it produces the following result:
Width: 5.5, Height: 3.0Area: 16.5Initializing the Base Class Constructor
Section titled “Initializing the Base Class Constructor”A derived class constructor must call a constructor of its base class. If you don’t explicitly call a base constructor, the compiler will try to call the default (parameterless) constructor of the base class. To call a specific base class constructor, you use the base keyword in the derived class’s constructor declaration.
Example
Section titled “Example”Here’s an example showing how a Tabletop class can initialize its Rectangle base class using a constructor.
using System;
namespace BaseInitialization{ public class Rectangle { public double Length { get; } public double Width { get; }
// Base class constructor public Rectangle(double length, double width) { Length = length; Width = width; }
public double GetArea() => Length * Width;
public virtual void Display() { Console.WriteLine($"Length: {Length}"); Console.WriteLine($"Width: {Width}"); Console.WriteLine($"Area: {GetArea()}"); } }
public class Tabletop : Rectangle { public decimal CostPerSquareUnit { get; set; }
// Derived class constructor calling the base constructor public Tabletop(double length, double width, decimal costPerSquareUnit) : base(length, width) { CostPerSquareUnit = costPerSquareUnit; }
public decimal GetTotalCost() => (decimal)GetArea() * CostPerSquareUnit;
// Override the Display method to add more info public override void Display() { base.Display(); // Call the base class's Display method Console.WriteLine($"Total Cost: {GetTotalCost():C}"); // :C formats as currency } }
public class Program { public static void Main(string[] args) { var table = new Tabletop(4.5, 7.5, 70m); // 'm' suffix for decimal table.Display(); } }}When the above code is compiled and executed, it produces the following result:
Length: 4.5Width: 7.5Area: 33.75Total Cost: $2,362.50Method Overriding
Section titled “Method Overriding”A derived class can provide its own implementation of a method that it inherited from a base class. To override a method, the base class method must be marked with the virtual, abstract, or override keyword. The derived class method must then use the override keyword.
Example
Section titled “Example”This example demonstrates polymorphism, where an Animal variable can hold a Dog object, and calling MakeSound() executes the overridden method from the Dog class.
using System;
public class Animal{ public virtual void MakeSound() { Console.WriteLine("Some generic animal sound"); }}
public class Dog : Animal{ public override void MakeSound() { Console.WriteLine("Woof! Woof!"); }}
public class Cat : Animal{ public override void MakeSound() { Console.WriteLine("Meow"); }}
public class Program{ public static void Main() { Animal myAnimal = new Animal(); Animal myDog = new Dog(); // A Dog is an Animal Animal myCat = new Cat(); // A Cat is an Animal
myAnimal.MakeSound(); myDog.MakeSound(); myCat.MakeSound(); }}When executed, this program outputs:
Some generic animal soundWoof! Woof!MeowPreventing Inheritance with sealed
Section titled “Preventing Inheritance with sealed”You can prevent a class from being used as a base class by marking it with the sealed keyword. This is useful for classes that are not designed to be extended. For example, the string class in .NET is sealed.
public sealed class FinalClass{ public void ShowMessage() { Console.WriteLine("This class cannot be inherited."); }}
// The following line would cause a compilation error:// public class AttemptToDerive : FinalClass { } // Error: 'AttemptToDerive': cannot derive from sealed type 'FinalClass'Multiple Inheritance via Interfaces
Section titled “Multiple Inheritance via Interfaces”While C# does not support inheriting from multiple classes, a class can implement multiple interfaces. An interface defines a contract—a set of public methods and properties—that the implementing class must provide. This allows you to achieve polymorphism and code reuse in a safe and flexible way.
Best Practice: Prefer implementing interfaces over class inheritance when you only need to define a contract of capabilities (e.g., ISerializable, IComparable).
Example
Section titled “Example”Here, a Car class inherits from Vehicle and also implements the IDrivable and IChargeable interfaces, representing a modern electric car.
using System;
// Interface for things that can be drivenpublic interface IDrivable{ void Start(); void Stop(); void Drive();}
// Interface for things that can be chargedpublic interface IChargeable{ int BatteryLevel { get; } void Charge();}
// Base classpublic abstract class Vehicle{ public string Make { get; set; } public string Model { get; set; }}
// Derived class implementing multiple interfacespublic class ElectricCar : Vehicle, IDrivable, IChargeable{ public int BatteryLevel { get; private set; } = 50;
public void Start() { Console.WriteLine("Electric car started silently."); }
public void Stop() { Console.WriteLine("Regenerative braking engaged. Car stopped."); }
public void Drive() { if (BatteryLevel > 0) { Console.WriteLine("Driving the car, whirring sound."); BatteryLevel -= 5; } else { Console.WriteLine("Battery is empty!"); } }
public void Charge() { Console.WriteLine("Charging..."); BatteryLevel = 100; Console.WriteLine("Battery fully charged."); }}
public class Program{ public static void Main() { var myTesla = new ElectricCar { Make = "Tesla", Model = "Model Y" }; myTesla.Start(); myTesla.Drive(); Console.WriteLine($"Current battery: {myTesla.BatteryLevel}%"); myTesla.Charge(); Console.WriteLine($"Current battery: {myTesla.BatteryLevel}%"); myTesla.Stop(); }}When the above code is compiled and executed, it produces a result similar to this:
Electric car started silently.Driving the car, whirring sound.Current battery: 45%Charging...Battery fully charged.Current battery: 100%Regenerative braking engaged. Car stopped.