Appearance
Inheritance
Learn how to create class hierarchies and reuse code through inheritance in C#.
What You'll Learn
- Creating base and derived classes
- Using the base keyword
- Method overriding
- Abstract classes
- Sealed classes
What is Inheritance?
Inheritance allows a class to inherit properties and methods from another class, promoting code reuse.
┌─────────────┐
│ Animal │ ← Base class
│ - Name │
│ - Speak() │
└──────┬──────┘
│
┌───────────────┼───────────────┐
│ │ │
┌──────▼──────┐ ┌──────▼──────┐ ┌──────▼──────┐
│ Dog │ │ Cat │ │ Bird │
│ - Breed │ │ - Indoor │ │ - CanFly │
│ - Bark() │ │ - Meow() │ │ - Fly() │
└─────────────┘ └─────────────┘ └─────────────┘
↑
Derived classesBasic Inheritance
csharp
// Base class
class Animal
{
public string Name { get; set; }
public void Eat()
{
Console.WriteLine($"{Name} is eating.");
}
public void Sleep()
{
Console.WriteLine($"{Name} is sleeping.");
}
}
// Derived class
class Dog : Animal
{
public string Breed { get; set; }
public void Bark()
{
Console.WriteLine($"{Name} says: Woof!");
}
}
// Usage
Dog dog = new Dog
{
Name = "Buddy",
Breed = "Golden Retriever"
};
dog.Eat(); // Inherited from Animal
dog.Sleep(); // Inherited from Animal
dog.Bark(); // Defined in DogThe base Keyword
csharp
class Animal
{
public string Name { get; set; }
public Animal(string name)
{
Name = name;
Console.WriteLine("Animal constructor called");
}
public void Describe()
{
Console.WriteLine($"This is {Name}");
}
}
class Dog : Animal
{
public string Breed { get; set; }
// Call base constructor
public Dog(string name, string breed) : base(name)
{
Breed = breed;
Console.WriteLine("Dog constructor called");
}
public new void Describe()
{
base.Describe(); // Call base method
Console.WriteLine($"Breed: {Breed}");
}
}
Dog dog = new Dog("Buddy", "Labrador");
// Output:
// Animal constructor called
// Dog constructor called
dog.Describe();
// This is Buddy
// Breed: LabradorMethod Overriding
csharp
class Animal
{
public string Name { get; set; }
// Virtual allows overriding
public virtual void Speak()
{
Console.WriteLine("Some sound");
}
}
class Dog : Animal
{
// Override changes behavior
public override void Speak()
{
Console.WriteLine($"{Name} says: Woof!");
}
}
class Cat : Animal
{
public override void Speak()
{
Console.WriteLine($"{Name} says: Meow!");
}
}
class Cow : Animal
{
public override void Speak()
{
Console.WriteLine($"{Name} says: Moo!");
}
}
// Polymorphism in action
Animal[] animals = {
new Dog { Name = "Buddy" },
new Cat { Name = "Whiskers" },
new Cow { Name = "Bessie" }
};
foreach (Animal animal in animals)
{
animal.Speak(); // Calls the appropriate override
}
// Buddy says: Woof!
// Whiskers says: Meow!
// Bessie says: Moo!Abstract Classes
csharp
// Cannot be instantiated directly
abstract class Shape
{
public string Color { get; set; }
// Abstract method - must be implemented by derived classes
public abstract double GetArea();
// Regular method - can be inherited as-is
public void Describe()
{
Console.WriteLine($"A {Color} shape with area {GetArea():F2}");
}
}
class Rectangle : Shape
{
public double Width { get; set; }
public double Height { get; set; }
public override double GetArea()
{
return Width * Height;
}
}
class Circle : Shape
{
public double Radius { get; set; }
public override double GetArea()
{
return Math.PI * Radius * Radius;
}
}
// Usage
// Shape shape = new Shape(); // Error! Cannot instantiate abstract class
Shape rect = new Rectangle { Color = "Blue", Width = 5, Height = 3 };
Shape circle = new Circle { Color = "Red", Radius = 4 };
rect.Describe(); // A Blue shape with area 15.00
circle.Describe(); // A Red shape with area 50.27Sealed Classes
csharp
// Cannot be inherited
sealed class FinalClass
{
public void DoSomething()
{
Console.WriteLine("Doing something");
}
}
// class Derived : FinalClass { } // Error! Cannot inherit from sealed
// Sealing a method
class Base
{
public virtual void Method() { }
}
class Derived : Base
{
// Seal this override - subclasses can't override further
public sealed override void Method()
{
Console.WriteLine("Sealed implementation");
}
}Protected Members
csharp
class Animal
{
// Private - only this class
private int id;
// Protected - this class and subclasses
protected string species;
// Public - everyone
public string Name { get; set; }
protected void SetSpecies(string s)
{
species = s;
}
}
class Dog : Animal
{
public Dog()
{
// Can access protected members
species = "Canis familiaris";
SetSpecies("Dog");
// Cannot access private members
// id = 1; // Error!
}
}Type Checking and Casting
csharp
Animal animal = new Dog { Name = "Buddy" };
// Check type with 'is'
if (animal is Dog)
{
Console.WriteLine("It's a dog!");
}
// Pattern matching with 'is'
if (animal is Dog dog)
{
dog.Bark(); // Can use as Dog
}
// Cast with 'as' (returns null if fails)
Dog? maybeDog = animal as Dog;
if (maybeDog != null)
{
maybeDog.Bark();
}
// Direct cast (throws if fails)
Dog definitelyDog = (Dog)animal;
// Switch pattern matching
string description = animal switch
{
Dog d => $"Dog named {d.Name}",
Cat c => $"Cat named {c.Name}",
_ => "Unknown animal"
};Complete Example
csharp
using System;
using System.Collections.Generic;
abstract class Employee
{
public string Name { get; set; }
public string Id { get; }
protected decimal baseSalary;
private static int nextId = 1;
public Employee(string name, decimal baseSalary)
{
Name = name;
this.baseSalary = baseSalary;
Id = $"EMP{nextId++:D4}";
}
public abstract decimal CalculateSalary();
public virtual void DisplayInfo()
{
Console.WriteLine($"ID: {Id}");
Console.WriteLine($"Name: {Name}");
Console.WriteLine($"Salary: ${CalculateSalary():N2}");
}
}
class FullTimeEmployee : Employee
{
public int VacationDays { get; set; }
public FullTimeEmployee(string name, decimal salary)
: base(name, salary)
{
VacationDays = 20;
}
public override decimal CalculateSalary()
{
return baseSalary;
}
public override void DisplayInfo()
{
base.DisplayInfo();
Console.WriteLine($"Type: Full-Time");
Console.WriteLine($"Vacation Days: {VacationDays}");
}
}
class HourlyEmployee : Employee
{
public decimal HourlyRate { get; set; }
public int HoursWorked { get; set; }
public HourlyEmployee(string name, decimal hourlyRate)
: base(name, 0)
{
HourlyRate = hourlyRate;
}
public override decimal CalculateSalary()
{
decimal regularPay = Math.Min(HoursWorked, 40) * HourlyRate;
decimal overtimePay = Math.Max(0, HoursWorked - 40) * HourlyRate * 1.5m;
return regularPay + overtimePay;
}
public override void DisplayInfo()
{
Console.WriteLine($"ID: {Id}");
Console.WriteLine($"Name: {Name}");
Console.WriteLine($"Type: Hourly");
Console.WriteLine($"Rate: ${HourlyRate}/hour");
Console.WriteLine($"Hours: {HoursWorked}");
Console.WriteLine($"Salary: ${CalculateSalary():N2}");
}
}
class Manager : FullTimeEmployee
{
public List<Employee> Team { get; } = new List<Employee>();
public decimal Bonus { get; set; }
public Manager(string name, decimal salary, decimal bonus)
: base(name, salary)
{
Bonus = bonus;
VacationDays = 25; // Managers get more vacation
}
public override decimal CalculateSalary()
{
return base.CalculateSalary() + Bonus;
}
public void AddTeamMember(Employee emp)
{
Team.Add(emp);
}
public override void DisplayInfo()
{
base.DisplayInfo();
Console.WriteLine($"Bonus: ${Bonus:N2}");
Console.WriteLine($"Team Size: {Team.Count}");
}
}
class Program
{
static void Main()
{
var employees = new List<Employee>
{
new FullTimeEmployee("Alice Johnson", 75000),
new HourlyEmployee("Bob Smith", 25) { HoursWorked = 45 },
new Manager("Carol Williams", 95000, 15000)
};
Console.WriteLine("=== Employee Report ===\n");
decimal totalPayroll = 0;
foreach (var emp in employees)
{
emp.DisplayInfo();
Console.WriteLine();
totalPayroll += emp.CalculateSalary();
}
Console.WriteLine($"Total Payroll: ${totalPayroll:N2}");
}
}Summary
You've learned:
- Creating base and derived classes
- Using constructors with inheritance
- Virtual and override for polymorphism
- Abstract classes and methods
- Sealed classes and methods
- Type checking and casting
Next Steps
Continue to Interfaces to learn about contracts and abstraction!