.NET Inheritance
Introduction
Inheritance is one of the four fundamental principles of object-oriented programming (OOP), alongside encapsulation, abstraction, and polymorphism. In .NET, inheritance allows you to create a new class that reuses, extends, and modifies the behavior defined in another class. The class whose members are inherited is called the base class (or parent class), and the class that inherits those members is called the derived class (or child class).
Inheritance provides a powerful mechanism for code reuse and establishing hierarchical relationships between classes. It lets you build new classes on existing, well-tested classes, adding or modifying functionality while maintaining the original structure.
Basic Inheritance Syntax
In C#, inheritance is implemented using the colon (:
) syntax:
public class BaseClass
{
// Base class members
}
public class DerivedClass : BaseClass
{
// Derived class members
// Inherits all accessible members from BaseClass
}
Understanding Inheritance in .NET
Creating a Simple Inheritance Example
Let's start with a basic example to demonstrate inheritance:
using System;
// Base class
public class Animal
{
public string Name { get; set; }
public int Age { get; set; }
public void Eat()
{
Console.WriteLine($"{Name} is eating.");
}
public void Sleep()
{
Console.WriteLine($"{Name} is sleeping.");
}
}
// Derived class
public class Dog : Animal
{
public void Bark()
{
Console.WriteLine($"{Name} says: Woof woof!");
}
}
// Usage
public class Program
{
public static void Main()
{
// Creating an instance of the derived class
Dog myDog = new Dog
{
Name = "Rex",
Age = 3
};
// Accessing base class methods
myDog.Eat(); // Inherited from Animal
myDog.Sleep(); // Inherited from Animal
// Accessing derived class method
myDog.Bark(); // Defined in Dog
}
}
Output:
Rex is eating.
Rex is sleeping.
Rex says: Woof woof!
In this example, the Dog
class inherits properties (Name
and Age
) and methods (Eat
and Sleep
) from the Animal
class, while also defining its own method Bark
. When we create a Dog
instance, it can use both its own members and those inherited from the Animal
class.
Access Modifiers and Inheritance
When inheriting, the accessibility of the base class members in the derived class depends on their access modifiers:
- public: Accessible anywhere, including derived classes
- protected: Accessible within the base class and derived classes
- internal: Accessible within the same assembly
- protected internal: Accessible within the same assembly or derived classes
- private: Accessible only within the class they are defined (not inherited)
- private protected: Accessible only within the class they are defined or derived classes in the same assembly
Here's an example showing different access modifiers:
public class BaseClass
{
public string PublicField = "Public field";
protected string ProtectedField = "Protected field";
private string PrivateField = "Private field";
public void PrintFields()
{
Console.WriteLine(PublicField);
Console.WriteLine(ProtectedField);
Console.WriteLine(PrivateField);
}
}
public class DerivedClass : BaseClass
{
public void AccessFields()
{
Console.WriteLine(PublicField); // Accessible
Console.WriteLine(ProtectedField); // Accessible
// Console.WriteLine(PrivateField); // Error! Not accessible
}
}
Method Overriding
Inheritance allows derived classes to provide specific implementations of methods that are already defined in the base class. This is called method overriding and is accomplished using the virtual
keyword in the base class and the override
keyword in the derived class.
public class Animal
{
public string Name { get; set; }
public virtual void MakeSound()
{
Console.WriteLine("Animal makes a sound");
}
}
public class Dog : Animal
{
public override void MakeSound()
{
Console.WriteLine($"{Name} barks: Woof woof!");
}
}
public class Cat : Animal
{
public override void MakeSound()
{
Console.WriteLine($"{Name} meows: Meow!");
}
}
// Usage example
public class Program
{
public static void Main()
{
Animal myAnimal = new Animal() { Name = "Generic Animal" };
Dog myDog = new Dog() { Name = "Rex" };
Cat myCat = new Cat() { Name = "Whiskers" };
myAnimal.MakeSound(); // Calls Animal's MakeSound
myDog.MakeSound(); // Calls Dog's MakeSound
myCat.MakeSound(); // Calls Cat's MakeSound
// Polymorphism example
Animal[] animals = { myAnimal, myDog, myCat };
foreach (Animal animal in animals)
{
animal.MakeSound(); // Calls the appropriate MakeSound method
}
}
}
Output:
Animal makes a sound
Rex barks: Woof woof!
Whiskers meows: Meow!
Animal makes a sound
Rex barks: Woof woof!
Whiskers meows: Meow!
Base Keyword
The base
keyword is used to access members of the base class from within a derived class:
public class Animal
{
public virtual void Eat()
{
Console.WriteLine("Animal is eating");
}
}
public class Dog : Animal
{
public override void Eat()
{
// Call the base implementation first
base.Eat();
// Then add custom behavior
Console.WriteLine("Dog is eating enthusiastically");
}
}
Constructors and Inheritance
When you create an instance of a derived class, a constructor of the base class is always called first, followed by the constructor of the derived class.
public class Animal
{
public string Name { get; set; }
public Animal()
{
Console.WriteLine("Animal constructor called");
Name = "No name";
}
public Animal(string name)
{
Console.WriteLine("Animal parameterized constructor called");
Name = name;
}
}
public class Dog : Animal
{
public string Breed { get; set; }
public Dog() : base() // Explicitly calling base constructor (optional)
{
Console.WriteLine("Dog constructor called");
Breed = "Unknown";
}
public Dog(string name, string breed) : base(name) // Calling base constructor with parameter
{
Console.WriteLine("Dog parameterized constructor called");
Breed = breed;
}
}
// Usage
public class Program
{
public static void Main()
{
Dog dog1 = new Dog();
Console.WriteLine($"{dog1.Name}, {dog1.Breed}");
Console.WriteLine("--------------");
Dog dog2 = new Dog("Rex", "German Shepherd");
Console.WriteLine($"{dog2.Name}, {dog2.Breed}");
}
}
Output:
Animal constructor called
Dog constructor called
No name, Unknown
--------------
Animal parameterized constructor called
Dog parameterized constructor called
Rex, German Shepherd
Sealed Classes and Methods
In C#, you can prevent a class from being inherited or a method from being overridden by using the sealed
keyword:
// Sealed class - cannot be inherited from
public sealed class FinalClass
{
public void DoSomething() { }
}
// This would cause a compile error:
// public class DerivedFromFinal : FinalClass { }
public class BaseWithSealedMethod
{
public virtual void Method1() { }
// This method can be overridden once but not in further derived classes
public virtual void Method2() { }
}
public class DerivedWithSealedMethod : BaseWithSealedMethod
{
public override void Method1() { }
// Sealed override - cannot be overridden in derived classes
public sealed override void Method2() { }
}
public class ThirdGeneration : DerivedWithSealedMethod
{
public override void Method1() { } // This is fine
// This would cause a compile error:
// public override void Method2() { }
}
Practical Example: Building a Shape Hierarchy
Let's create a more complex example to demonstrate inheritance in a real-world scenario:
using System;
public abstract class Shape
{
// Properties
public string Name { get; set; }
public string Color { get; set; }
// Constructor
public Shape(string name, string color)
{
Name = name;
Color = color;
}
// Abstract method - must be implemented by derived classes
public abstract double CalculateArea();
// Virtual method - can be overridden
public virtual void DisplayInfo()
{
Console.WriteLine($"Shape: {Name}");
Console.WriteLine($"Color: {Color}");
}
}
public class Circle : Shape
{
public double Radius { get; set; }
public Circle(string color, double radius) : base("Circle", color)
{
Radius = radius;
}
public override double CalculateArea()
{
return Math.PI * Radius * Radius;
}
public override void DisplayInfo()
{
base.DisplayInfo();
Console.WriteLine($"Radius: {Radius}");
Console.WriteLine($"Area: {CalculateArea():F2}");
}
}
public class Rectangle : Shape
{
public double Width { get; set; }
public double Height { get; set; }
public Rectangle(string color, double width, double height) : base("Rectangle", color)
{
Width = width;
Height = height;
}
public override double CalculateArea()
{
return Width * Height;
}
public override void DisplayInfo()
{
base.DisplayInfo();
Console.WriteLine($"Width: {Width}");
Console.WriteLine($"Height: {Height}");
Console.WriteLine($"Area: {CalculateArea():F2}");
}
}
public class Triangle : Shape
{
public double Base { get; set; }
public double Height { get; set; }
public Triangle(string color, double baseLength, double height) : base("Triangle", color)
{
Base = baseLength;
Height = height;
}
public override double CalculateArea()
{
return 0.5 * Base * Height;
}
public override void DisplayInfo()
{
base.DisplayInfo();
Console.WriteLine($"Base: {Base}");
Console.WriteLine($"Height: {Height}");
Console.WriteLine($"Area: {CalculateArea():F2}");
}
}
public class Program
{
public static void Main()
{
Shape[] shapes = new Shape[3];
shapes[0] = new Circle("Red", 5);
shapes[1] = new Rectangle("Blue", 4, 6);
shapes[2] = new Triangle("Green", 8, 3);
foreach (Shape shape in shapes)
{
shape.DisplayInfo();
Console.WriteLine("------------------------");
}
}
}
Output:
Shape: Circle
Color: Red
Radius: 5
Area: 78.54
------------------------
Shape: Rectangle
Color: Blue
Width: 4
Height: 6
Area: 24.00
------------------------
Shape: Triangle
Color: Green
Base: 8
Height: 3
Area: 12.00
------------------------
This example demonstrates several important inheritance concepts:
- Abstract base class (
Shape
) defining common properties and methods - Abstract method (
CalculateArea
) that derived classes must implement - Method overriding with
virtual
andoverride
- Constructor chaining using
base
- Polymorphism when calling
DisplayInfo
on different shapes
Multiple Inheritance
C# does not support multiple inheritance for classes (inheriting from more than one class). However, it supports implementing multiple interfaces, which provides a form of multiple inheritance:
public interface IDrawable
{
void Draw();
}
public interface IPrintable
{
void Print();
}
// Inherits from Shape and implements two interfaces
public class Square : Shape, IDrawable, IPrintable
{
public double Side { get; set; }
public Square(string color, double side) : base("Square", color)
{
Side = side;
}
public override double CalculateArea()
{
return Side * Side;
}
// Implementing IDrawable
public void Draw()
{
Console.WriteLine($"Drawing a {Color} square");
}
// Implementing IPrintable
public void Print()
{
Console.WriteLine($"Printing a square with side {Side}");
}
}
Summary
Inheritance is a powerful feature in .NET that enables code reuse and hierarchical class relationships. Through inheritance:
- A derived class inherits members (fields, properties, methods) from its base class
- Method overriding allows specialized behavior in derived classes
- Access modifiers control which members are inherited
- Constructors can be chained using the
base
keyword - Abstract classes and methods provide templates for derived classes
- Sealed classes and methods prevent further inheritance
- C# supports single inheritance for classes but multiple interface implementation
Understanding inheritance is crucial for building well-structured, maintainable .NET applications, as it helps reduce code duplication and creates logical relationships between classes.
Exercises
-
Create a
Vehicle
base class with properties forMake
,Model
, andYear
. Then create derived classes forCar
,Motorcycle
, andTruck
with specific properties and methods for each. -
Implement a library system with a base
LibraryItem
class and derived classes forBook
,DVD
, andMagazine
. Include methods for checking items out and returning them. -
Create a banking system with a
BankAccount
base class and derivedSavingsAccount
andCheckingAccount
classes with different interest calculation methods.
Additional Resources
- Microsoft Docs: Inheritance
- Microsoft Docs: Polymorphism
- C# Corner: Inheritance in C#
- Book: "C# in Depth" by Jon Skeet, which covers OOP principles in depth
If you spot any mistakes on this website, please let me know at [email protected]. I’d greatly appreciate your feedback! :)