C# · Chapter 3.11 · Pro level

Inheritance & Polymorphism (Enemy → Boss)

Inheritance और Polymorphism (Enemy → Boss)

A game has many enemies — Goblin, Skeleton, Dragon Boss. They all have a name, health and an attack. Instead of copying the same code again and again, we write it once in a parent class Enemy and create child classes with class Boss : Enemy. The child inherits (gets) everything from the parent, just like a child gets the family surname. The parent marks a method virtual (children may change this) and the child writes override to give its own version. : base(name, health) sends values up to the parent's constructor. Now the magic: put all enemies in ONE List<Enemy> and call e.Attack() — every object runs ITS OWN version. One call, many forms = polymorphism. (An abstract method has no body at all, and every child MUST override it.)

गेम में बहुत सारे दुश्मन होते हैं — Goblin, Skeleton, Dragon Boss। सबके पास नाम, health और हमला होता है। एक ही कोड बार-बार कॉपी करने की जगह हम उसे एक बार parent class Enemy में लिखते हैं और class Boss : Enemy से child classes बनाते हैं। Child, parent की सारी चीज़ें विरासत में (inherit) पा लेता है — जैसे बच्चे को परिवार का सरनेम मिलता है। Parent किसी method को virtual लिखता है (बच्चे इसे बदल सकते हैं) और child override लिखकर अपना version देता है। : base(name, health) वैल्यू ऊपर parent के constructor को भेजता है। अब जादू: सारे दुश्मन एक ही List<Enemy> में रखो और e.Attack() बुलाओ — हर object अपना ख़ुद का version चलाता है। एक कॉल, कई रूप = polymorphism। (abstract method की कोई body नहीं होती, और हर child को उसे override करना ही पड़ता है।)

In the classroom you can run and edit this code in your browser, get hints and mark the chapter as done. क्लास में यह code ब्राउज़र में चलाकर बदल सकते हो।

Words and symbols in this chapter

class Boss : Enemy
Boss is a child of Enemy and gets all its fields and methods.
Boss, Enemy का child है और उसके सारे fields और methods पाता है।
public virtual void Attack()
The parent version; virtual allows children to replace it.
Parent वाला version; virtual बच्चों को इसे बदलने देता है।
public override void Attack()
The child’s own version of the same method.
उसी method का child वाला अपना version।
: base(name, health)
Calls the parent constructor first, so Name and Health are set.
पहले parent का constructor बुलाता है, ताकि Name और Health सेट हो जाएँ।
List<Enemy> wave
One list can hold Enemy AND Boss objects (a Boss is an Enemy).
एक list में Enemy और Boss दोनों objects रह सकते हैं (Boss भी एक Enemy है)।
abstract
A method with no body that every child must override; an abstract class cannot be created with new.
बिना body वाला method जिसे हर child को override करना पड़ता है; abstract class से new नहीं बनता।

Ready example

using System;
using System.Collections.Generic;

class Enemy {
    public string Name;
    public int Health;

    public Enemy(string name, int health) {
        Name = name;
        Health = health;
    }

    public virtual void Attack() {
        Console.WriteLine(Name + " hits you for 5 damage");
    }
}

class Boss : Enemy {
    public int Rage;

    public Boss(string name, int health, int rage) : base(name, health) {
        Rage = rage;
    }

    public override void Attack() {
        Console.WriteLine(Name + " breathes FIRE for " + (10 * Rage) + " damage!");
    }
}

class Program {
    static void Main() {
        List<Enemy> wave = new List<Enemy>();
        wave.Add(new Enemy("Goblin", 30));
        wave.Add(new Enemy("Skeleton", 40));
        wave.Add(new Boss("Dragon King", 500, 3));

        foreach (Enemy e in wave) {
            e.Attack();
        }
        Console.WriteLine("Enemies in wave: " + wave.Count);
    }
}

What you will see: Each enemy attacks in turn — the Dragon King uses its own override.

हर दुश्मन बारी-बारी हमला करता है — Dragon King अपना override वाला हमला करता है।

Line by line

class Enemy { ... public virtual void Attack() { ... } }
The shared blueprint for every enemy.
हर दुश्मन का साझा नक्शा।
class Boss : Enemy { ... : base(name, health) ... }
Boss reuses Enemy and adds its own Rage.
Boss, Enemy को दोबारा इस्तेमाल करता है और अपना Rage जोड़ता है।
public override void Attack() { ... }
The Boss breathes fire instead of a normal hit.
Boss सामान्य वार की जगह आग उगलता है।
foreach (Enemy e in wave) { e.Attack(); }
The same call: Goblin hits, Dragon breathes fire (polymorphism).
एक ही कॉल: Goblin मारता है, Dragon आग उगलता है (polymorphism)।

Common mistake

✗ Wrong

class Enemy {
    public void Attack() { }
}
class Boss : Enemy {
    public override void Attack() { }
}

✓ Right

class Enemy {
    public virtual void Attack() { }
}
class Boss : Enemy {
    public override void Attack() { }
}

You can only override a method that the parent marked virtual (or abstract) — otherwise you get error CS0506.

आप सिर्फ़ उसी method को override कर सकते हो जिसे parent ने virtual (या abstract) लिखा हो — वरना error CS0506 आती है।

Your task

Create class Archer : Enemy whose constructor calls base(name, 60) and which overrides Attack() to print <Name> shoots an arrow!. Then add new Archer("Robin") to the wave.

class Archer : Enemy बनाओ जिसका constructor base(name, 60) बुलाए और जो Attack() को override करके <Name> shoots an arrow! छापे। फिर wave में new Archer("Robin") जोड़ो।

  1. Below class Enemy, write class Archer : Enemy { and close it with }.
    class Enemy के नीचे class Archer : Enemy { लिखो और } से बंद करो।
  2. Inside: public Archer(string name) : base(name, 60) { } and public override void Attack() { Console.WriteLine(Name + " shoots an arrow!"); }.
    अंदर: public Archer(string name) : base(name, 60) { } और public override void Attack() { Console.WriteLine(Name + " shoots an arrow!"); }।
  3. In Main add wave.Add(new Archer("Robin")); and Run — you should see Robin shoots an arrow!.
    Main में wave.Add(new Archer("Robin")); जोड़कर Run करो — Robin shoots an arrow! दिखना चाहिए।
Starter code for the task
using System;
using System.Collections.Generic;

class Enemy {
    public string Name;
    public int Health;

    public Enemy(string name, int health) {
        Name = name;
        Health = health;
    }

    public virtual void Attack() {
        Console.WriteLine(Name + " hits you!");
    }
}

// TODO 1: class Archer : Enemy banao
// TODO 2: uska constructor: public Archer(string name) : base(name, 60) { }
// TODO 3: public override void Attack() jo  Name + " shoots an arrow!"  print kare

class Program {
    static void Main() {
        List<Enemy> wave = new List<Enemy>();
        wave.Add(new Enemy("Goblin", 30));
        // TODO 4: wave.Add(new Archer("Robin")); jodo

        foreach (Enemy e in wave) {
            e.Attack();
        }
    }
}

Do this task in the classroom: your code is checked automatically and you get hints if something is missing.

Recap

Quick quiz

Enemy e = new Boss("Dragon", 500, 3); e.Attack(); — Boss overrides Attack(). Which version runs?

Enemy e = new Boss("Dragon", 500, 3); e.Attack(); — Boss ने Attack() override किया है। कौन-सा version चलेगा?

  1. Enemy.Attack()
  2. Boss.Attack() — the real type of the object decides
  3. Both, one after the other
  4. A compile error
Show the answer

Answer: B (Boss.Attack() — the real type of the object decides)

With virtual/override, C# runs the version of the object’s real class — that is polymorphism.

virtual/override के साथ C# object की असली class वाला version चलाता है — यही polymorphism है।

Practice problems for this chapter

Solve them in the Practice Zone, where each answer is checked automatically and two hints are available.