C# & .NET Framework Advanced OOP — Mastering the Craft
💡
Exercise 39

Polymorphism — One Interface, Many Forms 20 XP Hard

Ctrl+Enter Run Ctrl+S Save

🌊 Polymorphism: Many Forms, One Name

Polymorphism means "many forms." It allows objects of different classes to be treated through the same base type, yet each responds in its own way. You call the same method on different objects, and each one behaves according to its actual type at runtime.

Picture an earthquake hitting a city. The same seismic force hits every building — but a wood house flexes, a steel tower absorbs shock, and a brick building cracks. Same event, different responses. That's polymorphism.

virtual and override — Runtime Polymorphism

Mark a base method as virtual to allow derived classes to override it. When you call the method through a base-type reference, C# looks up the actual type at runtime and calls the overridden version. This is called runtime (dynamic) polymorphism.

class Building { public string Name; public Building(string name) { Name = name; } // virtual — can be overridden by derived classes public virtual string Withstand() { return "Standing..."; } } class WoodHouse : Building { public WoodHouse(string name) : base(name) { } public override string Withstand() { return "Flexing structure... Survived!"; } } class SteelTower : Building { public SteelTower(string name) : base(name) { } public override string Withstand() { return "Absorbing shock... Survived!"; } } // Polymorphism in action: Building b = new WoodHouse("Cabin"); // base-type reference Console.WriteLine(b.Withstand()); // Calls WoodHouse.Withstand()!

Method Hiding with new

If a derived class declares a method with the same name as a base method without using override, it hides the base method. The compiler warns you — adding the new keyword makes the hiding explicit. Unlike override, hiding does not participate in polymorphism: the method called depends on the reference type, not the object type.

class Base { public virtual void Greet() => Console.WriteLine("Hello from Base"); } class DerivedOverride : Base { public override void Greet() => Console.WriteLine("Hello from Override"); } class DerivedNew : Base { public new void Greet() => Console.WriteLine("Hello from New"); } Base a = new DerivedOverride(); a.Greet(); // "Hello from Override" — polymorphism works! Base b = new DerivedNew(); b.Greet(); // "Hello from Base" — hiding! Reference type wins

The is and as Operators — Type Checking at Runtime

Use is to check if an object is of a certain type. Use as to attempt a safe cast — it returns null instead of throwing an exception if the cast fails.

Building building = new WoodHouse("Pine Lodge"); // is — returns true/false if (building is WoodHouse) Console.WriteLine("It's a wood house!"); // is with pattern matching (C# 7+) if (building is WoodHouse wood) Console.WriteLine($"Wood house: {wood.Name}"); // as — safe cast, returns null on failure SteelTower tower = building as SteelTower; if (tower == null) Console.WriteLine("Not a steel tower.");
  • virtual — marks a method as overridable in derived classes
  • override — replaces the base virtual method; polymorphism works through base references
  • new (hiding) — hides the base method; no polymorphism — reference type determines call
  • is — checks runtime type of an object (returns bool)
  • as — safe cast that returns null on failure instead of throwing
  • Runtime polymorphism — the actual object type (not reference type) determines which override runs

🏗️ Why Polymorphism Matters

Without polymorphism, you'd need endless if/else chains checking the type of each object. With it, you store different building types in a single Building[] array and call the same method — the correct version runs automatically. This is the foundation of extensible, maintainable software.

📋 Instructions
**Your Mission: Simulate an Earthquake Across the City!** Create a base `Building` class and three derived classes that respond differently to an earthquake. 1. Create a `Building` class: - `public string Name` field - Constructor takes a `string name` - A `virtual` method `public virtual string Withstand()` that returns `"Standing..."` 2. Create `WoodHouse : Building`: - Constructor calls `base(name)` - Override `Withstand()` to return `"Flexing structure... Survived!"` 3. Create `SteelTower : Building`: - Constructor calls `base(name)` - Override `Withstand()` to return `"Absorbing shock... Survived!"` 4. Create `BrickBuilding : Building`: - Constructor calls `base(name)` - Override `Withstand()` to return `"Cracking detected... Damage!"` 5. In `Main`: - Print `"Earthquake simulation:"` - Create a `Building[]` array with: `new WoodHouse("Wood House")`, `new SteelTower("Steel Tower")`, `new BrickBuilding("Brick Building")` - Loop through the array and print `"{Name}: {Withstand()}"` for each - Print `"Polymorphism in action!"`
Store all buildings in a `Building[]` array. When you call `building.Withstand()` through the base-type array, C# automatically calls the overridden version for each actual type. That's the power of `virtual` + `override`.
main.py
Hi! I'm Rex 👋
Output
Ready. Press ▶ Run or Ctrl+Enter.