# 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 November 3, 2026

## 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 `virtual` method can be overridden: the derived class writes it again, marked `override`, 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 `override` hides the inherited one instead of overriding it: treat that warning as an error.
- Override `ToString()` to describe an object. `Console.WriteLine` and 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.*

```csharp
Character hero = new Character("Hero");
Archer robin = new Archer("Robin");

hero.LevelUp();
robin.LevelUp();

Console.WriteLine($"{hero.Name}: level {hero.Level}, health {hero.Health}");
Console.WriteLine($"{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++;
    }
}
```

```text
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:

```csharp
Knight lancelot = new Knight("Lancelot", 4);
lancelot.TakeDamage(10);
Console.WriteLine($"{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));
    }
}
```

```text
Lancelot: health 94
```

## Forgetting virtual

Only a `virtual` method can be overridden. Without it:

```csharp
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();
    }
}
```

```text
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:

```csharp
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 $"{Name} (level {Level})";
    }
}

public class Archer : Character
{
    public Archer(string name) : base(name)
    {
    }
}
```

```text
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.

## Key terms

- [Method Overriding](https://www.ask-codey.com/glossary/method-overriding-c-sharp)
- [Virtual Method](https://www.ask-codey.com/glossary/virtual-method)
- [base](https://www.ask-codey.com/glossary/base-c-sharp)
- [ToString()](https://www.ask-codey.com/glossary/tostring-c-sharp)

## Cheat sheets

- [Overriding Methods](https://www.ask-codey.com/cheat-sheets/introduction-to-inheritance-in-csharp-overriding-methods-cheat-sheet)

Source: https://www.ask-codey.com/lessons/introduction-to-inheritance-in-csharp-overriding-methods
