Overriding Methods
A base class marks a method virtual so derived classes may change it; a derived class replaces it with override, and can still run the base version with base.MethodName().
Journeyman · C# · OOP · Updated
After this lesson you can
- Override a virtual method in a derived class
- Run the base class's version of a method from an override with base.
- Override ToString() to describe an object
Key takeaways
- Only a
virtualmethod can be overridden: the derived class writes it again, markedoverride, to replace the base version. base.LevelUp()inside an override runs the base version. Leave it out, and the override replaces the base version completely.- Writing the method without
overridehides the inherited one instead of overriding it: treat that warning as an error. - Override
ToString()to describe an object.Console.WriteLineand string interpolation call it for you.
A derived class inherits its base class's methods as they are. Sometimes one needs to work a little differently. When a character levels up, its level goes up by 1 and its health by 10. An archer should do all that and get an extra arrow.
Replacing an inherited method in a derived class is called overriding it.
virtual and override
Overriding takes a keyword on each side:
- The base class marks the method
virtual: derived classes may change this. - The derived class writes the method again, marked
override: this replaces the base version.
Character hero = new Character("Hero");
Archer robin = new Archer("Robin");
hero.LevelUp();
robin.LevelUp();
Console.WriteLine( quot;{hero.Name}: level {hero.Level}, health {hero.Health}");
Console.WriteLine( quot;{robin.Name}: level {robin.Level}, health {robin.Health}, arrows {robin.Arrows}");
public class Character
{
public string Name { get; }
public int Health { get; protected set; } = 100;
public int Level { get; protected set; } = 1;
public Character(string name)
{
Name = name;
}
public virtual void LevelUp()
{
Level++;
Health += 10;
}
}
public class Archer : Character
{
public int Arrows { get; private set; }
public Archer(string name) : base(name)
{
}
public override void LevelUp()
{
base.LevelUp();
Arrows++;
}
}
Hero: level 2, health 110
Robin: level 2, health 110, arrows 1
Properties work the same way. A base class can write public virtual string Title => "Adventurer";, and a derived class public override string Title => "Archer";.
base. runs the base version
Inside the override, base.LevelUp() runs Character's version first: level up, plus 10 health. Then the archer adds its arrow. The override changes only what's different, and reuses the rest.
Leave out base.LevelUp(), and the override replaces the base version completely: the archer would get an arrow, but no new level and no health.
The call can go anywhere in the override. A knight's armor absorbs part of every hit, so Knight lowers the damage before passing it on:
Knight lancelot = new Knight("Lancelot", 4);
lancelot.TakeDamage(10);
Console.WriteLine( quot;{lancelot.Name}: health {lancelot.Health}");
public class Character
{
public string Name { get; }
public int Health { get; protected set; } = 100;
public Character(string name)
{
Name = name;
}
public virtual void TakeDamage(int damage)
{
Health = Math.Max(Health - damage, 0);
}
}
public class Knight : Character
{
public int Armor { get; }
public Knight(string name, int armor) : base(name)
{
Armor = armor;
}
public override void TakeDamage(int damage)
{
base.TakeDamage(Math.Max(damage - Armor, 0));
}
}
Lancelot: health 94
Forgetting virtual
Only a virtual method can be overridden. Without it:
Archer robin = new Archer();
robin.LevelUp();
public class Character
{
public int Level { get; protected set; } = 1;
public void LevelUp()
{
Level++;
}
}
public class Archer : Character
{
public override void LevelUp()
{
base.LevelUp();
}
}
error CS0506: 'Archer.LevelUp()': cannot override inherited member 'Character.LevelUp()' because it is not marked virtual, abstract, or override
And if you leave out override instead, writing a plain public void LevelUp() in Archer, C# warns that the method hides the inherited one. Hiding isn't overriding, and it behaves differently in ways Polymorphism will show: treat that warning as an error, and add override.
Overriding ToString
Every class inherits ToString() from object, and it's virtual. Its standard version just returns the class's full name (with its namespace, such as CafeMenu.Pastry, if it has one), which isn't much use. Override it to describe the object:
Archer robin = new Archer("Robin");
Console.WriteLine(robin);
public class Character
{
public string Name { get; }
public int Level { get; protected set; } = 1;
public Character(string name)
{
Name = name;
}
public override string ToString()
{
return quot;{Name} (level {Level})";
}
}
public class Archer : Character
{
public Archer(string name) : base(name)
{
}
}
Robin (level 1)
Console.WriteLine calls ToString() on any object it's given, and string interpolation does too. Archer inherits Character's override, so archers describe themselves the same way.
Check yourself
3 questions to try on the lesson page.
So what
virtual invites a change, override makes it, and base. keeps the parts worth keeping. Each kind of character behaves its own way, while the shared behavior still lives in one place.