Chapter 12: Inheritance
1. What is Inheritance? (Super Simple Analogy)
Think of inheritance like a family tree:
- Base class (Parent) → has common traits that all children share Example: Vehicle has Speed, Color, StartEngine()
- Derived class (Child) → inherits everything from the parent and can add its own special features Example: Car inherits from Vehicle and adds NumberOfDoors, Drift()
- Grandchild → can inherit from Car Example: SportsCar inherits from Car and adds TurboBoost()
Key benefit: You don’t repeat code — common behavior lives in the base class.
2. Defining Base and Derived Classes
Syntax:
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
class BaseClass { // Common fields, properties, methods } class DerivedClass : BaseClass // ← : means "inherits from" { // Additional fields, properties, methods // Can also override or hide base members } |
Real example – Vehicle hierarchy
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
class Vehicle { public string Brand { get; set; } public int Speed { get; protected set; } // protected = child classes can access public Vehicle(string brand) { Brand = brand; Speed = 0; } public void StartEngine() { Console.WriteLine($"{Brand} engine started! Vroom! 🚗"); } public virtual void Move() // virtual = child can override this { Console.WriteLine($"{Brand} is moving at {Speed} km/h"); } public void Stop() { Speed = 0; Console.WriteLine($"{Brand} stopped."); } } |
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
class Car : Vehicle { public int NumberOfDoors { get; set; } public Car(string brand, int doors) : base(brand) { NumberOfDoors = doors; } // Override the base Move() method public override void Move() { Speed += 20; // Car accelerates faster Console.WriteLine($"{Brand} car is driving smoothly at {Speed} km/h with {NumberOfDoors} doors!"); } public void Honk() { Console.WriteLine("Beep beep! 🚗"); } } |
|
0 1 2 3 4 5 6 7 8 9 10 11 |
// Usage var myCar = new Car("Toyota", 4); myCar.StartEngine(); // Inherited from Vehicle myCar.Move(); // Calls Car's overridden version myCar.Honk(); // Car's own method myCar.Stop(); // Inherited from Vehicle |
Output:
|
0 1 2 3 4 5 6 7 8 9 |
Toyota engine started! Vroom! 🚗 Toyota car is driving smoothly at 20 km/h with 4 doors! Beep beep! 🚗 Toyota stopped. |
3. virtual & override – The Magic of Polymorphism
- virtual → Marks a method/property in base class as overridable
- override → In derived class, provides a new implementation
This is the key to polymorphism — treating different objects the same way but getting different behavior.
Example – Animals talking differently
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 |
class Animal { public virtual void MakeSound() { Console.WriteLine("Some generic animal sound..."); } } class Dog : Animal { public override void MakeSound() { Console.WriteLine("Woof woof! 🐶"); } } class Cat : Animal { public override void MakeSound() { Console.WriteLine("Meow meow! 🐱"); } } // Polymorphism in action Animal[] animals = new Animal[] { new Dog(), new Cat(), new Animal() }; foreach (Animal animal in animals) { animal.MakeSound(); // Calls the correct version! } |
Output:
|
0 1 2 3 4 5 6 7 8 |
Woof woof! 🐶 Meow meow! 🐱 Some generic animal sound... |
4. new Keyword – Hiding (Not Overriding) Base Members
If you don’t use virtual/override, you can hide the base method using new.
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
class BaseClass { public void ShowMessage() { Console.WriteLine("Message from BaseClass"); } } class DerivedClass : BaseClass { public new void ShowMessage() // Hides base version { Console.WriteLine("Message from DerivedClass"); } } BaseClass obj1 = new DerivedClass(); obj1.ShowMessage(); // "Message from BaseClass" (because variable type is BaseClass) DerivedClass obj2 = new DerivedClass(); obj2.ShowMessage(); // "Message from DerivedClass" |
Rule of thumb: Use override when you want polymorphic behavior (most common). Use new only when you really want to hide the base method (rare, can be confusing).
5. Sealed Classes & Sealed Methods
- sealed class → Cannot be inherited from (final class)
|
0 1 2 3 4 5 6 7 8 9 10 11 12 |
sealed class Calculator { public int Add(int a, int b) => a + b; } // This will cause compile error: // class AdvancedCalculator : Calculator { } // Error! |
- sealed override → Child class prevents further overriding
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
class Vehicle { public virtual void Move() { ... } } class Car : Vehicle { public sealed override void Move() // No one can override Move() anymore { // Special car movement } } class SportsCar : Car { // public override void Move() { ... } // ERROR! sealed prevents this } |
When to use sealed?
- When you don’t want anyone to extend your class/method (security, performance, design decision)
- Common in utility classes, final implementations
Mini-Project: Employee Hierarchy with Inheritance
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 |
class Employee { public string Name { get; set; } public decimal BaseSalary { get; protected set; } public Employee(string name, decimal baseSalary) { Name = name; BaseSalary = baseSalary; } public virtual decimal CalculateSalary() { return BaseSalary; } public virtual void Work() { Console.WriteLine($"{Name} is doing general work."); } } class Developer : Employee { public int LinesOfCodePerDay { get; set; } public Developer(string name, decimal baseSalary, int codeLines) : base(name, baseSalary) { LinesOfCodePerDay = codeLines; } public override decimal CalculateSalary() { return BaseSalary + (LinesOfCodePerDay * 10m); // Bonus per line } public override void Work() { Console.WriteLine($"{Name} is writing {LinesOfCodePerDay} lines of beautiful C# code! 💻"); } } class Manager : Employee { public int TeamSize { get; set; } public Manager(string name, decimal baseSalary, int team) : base(name, baseSalary) { TeamSize = team; } public sealed override decimal CalculateSalary() { return BaseSalary + (TeamSize * 5000m); // Bonus per team member } public override void Work() { Console.WriteLine($"{Name} is managing a team of {TeamSize} people! 👔"); } } // Usage Employee[] staff = new Employee[] { new Developer("Webliance", 80000, 300), new Manager("Priya", 120000, 12), new Employee("Rahul", 50000) }; foreach (Employee emp in staff) { emp.Work(); Console.WriteLine($"Salary: ₹{emp.CalculateSalary():N2}\n"); } |
Summary – What We Learned Today
- Inheritance → class Child : Parent
- virtual & override → polymorphic behavior
- new → hides base member (rarely used)
- sealed → prevents further inheritance/overriding
- base keyword → call parent constructor/method
- Polymorphism → treat derived objects as base type
Your Homework (Super Fun & Practical!)
- Create a new console project called InheritanceMaster
- Create a base class Shape with:
- Properties: Color
- virtual method: Draw() and CalculateArea()
- Create derived classes:
- Circle (Radius)
- Rectangle (Width, Height)
- Triangle (Base, Height)
- Override Draw() and CalculateArea() for each
- In Program.cs: Create an array of Shapes, draw each, and calculate total area
Next lesson: Polymorphism in Depth + Abstract Classes & Interfaces – we’re going to make our code even more flexible and powerful!
You’re doing absolutely fantastic! 🎉 Any part confusing? Want more examples with virtual, override, or sealed? Just tell me — I’m right here for you! 💙
