C# Inheritance
Reusing code through parent-child relationships
🔗 What is Inheritance?
Inheritance allows a class to inherit properties and methods from another class. It promotes code reusability and establishes a parent-child relationship between classes.
// Parent class
class Animal {
public void Eat() {
Console.WriteLine("Eating...");
}
}
// Child class inherits from Animal
class Dog : Animal {
public void Bark() {
Console.WriteLine("Barking...");
}
}
Output:
Eating...
Barking...
Key Inheritance Concepts
Base Class
The parent class being inherited
class Vehicle {
public string brand;
}
Derived Class
The child class that inherits
class Car : Vehicle {
public int doors;
}
Code Reuse
Use parent class features
Car myCar = new Car();
myCar.brand = "Toyota";
Protected
Accessible in derived classes
protected string model;
🔹 Basic Inheritance Example
Inheritance allows a derived class, like Student, to inherit fields and methods from a base class, Person. The child class extends functionality—adding a School property—while reusing common code like Name and Age. This promotes the DRY principle, reduces duplication, and organizes code hierarchically. For example, a Person introduces themselves, and a Student adds their study details, demonstrating code reuse and logical class relationships.
// Base class
class Person {
public string Name;
public int Age;
public void Introduce() {
Console.WriteLine($"Hi, I'm {Name}, {Age} years old.");
}
}
// Derived class
class Student : Person {
public string School;
public void Study() {
Console.WriteLine($"{Name} is studying at {School}.");
}
}
// Usage
Student student = new Student();
student.Name = "Alice";
student.Age = 20;
student.School = "MIT";
student.Introduce(); // From Person class
student.Study(); // From Student class
Output:
Hi, I'm Alice, 20 years old.
Alice is studying at MIT.
🔹 Constructor Inheritance
Derived classes use the base keyword to invoke parent constructors, ensuring proper initialization of inherited properties. A Manager class, inheriting from Employee, might call base(name, department) and then set additional properties like Salary. This mechanism maintains encapsulation, avoids code duplication in constructors, and guarantees that the object is fully and correctly initialized across the inheritance chain.
class Employee {
public string Name;
public double Salary;
public Employee(string name, double salary) {
Name = name;
Salary = salary;
}
}
class Manager : Employee {
public string Department;
// Call base constructor
public Manager(string name, double salary, string dept)
: base(name, salary) {
Department = dept;
}
public void ShowInfo() {
Console.WriteLine($"{Name} manages {Department}");
Console.WriteLine($"Salary: ${Salary}");
}
}
// Usage
Manager mgr = new Manager("Bob", 75000, "IT");
mgr.ShowInfo();
Output:
Bob manages IT
Salary: $75000
🔹 Method Overriding
Method overriding lets a derived class provide a specific implementation for a method marked as virtual in the base class. Using the override keyword, a Square class can redefine a Draw method differently from a Circle. This enables polymorphism, where a Shape reference can invoke the correct Draw behavior at runtime. Overriding is key for extensible frameworks, allowing subclasses to customize inherited behavior.
class Shape {
public virtual void Draw() {
Console.WriteLine("Drawing a shape");
}
}
class Circle : Shape {
public override void Draw() {
Console.WriteLine("Drawing a circle");
}
}
class Square : Shape {
public override void Draw() {
Console.WriteLine("Drawing a square");
}
}
// Usage
Shape shape1 = new Circle();
Shape shape2 = new Square();
shape1.Draw();
shape2.Draw();
Output:
Drawing a circle
Drawing a square
🔹 Protected Members
Protected members are accessible only within the declaring class and its derived classes, not by external code. For example, a BankAccount base class might have a protected Balance field that a SavingsAccount subclass can modify directly via a Deposit method. This maintains encapsulation within the class hierarchy while allowing controlled sharing, striking a balance between data hiding and inheritance-based access.
class BankAccount {
protected double balance;
public BankAccount(double initialBalance) {
balance = initialBalance;
}
}
class SavingsAccount : BankAccount {
private double interestRate = 0.05;
public SavingsAccount(double initialBalance)
: base(initialBalance) { }
public void AddInterest() {
balance += balance * interestRate;
Console.WriteLine($"New balance: ${balance}");
}
}
// Usage
SavingsAccount account = new SavingsAccount(1000);
account.AddInterest();
Output:
New balance: $1050