Understanding C#: Using virtual and override

By Andrew Stellman
October 27, 2009

The virtual and override keywords are an important part of inheritance in C#, but a lot of developers run into trouble with them. This post shows demystifies virtual and override, with step-by-step examples.

One of our Head First C# readers posted a question on the book's forum:

I don't understanding why I need to add 'virtual' keyword and 'override' keyword to make Penguin Fly() override Bird Fly(). [page 226]

I think

public class Penguin: Bird {
    public void Fly() {
        MessageBox.Show("Penguins can't fly");
    }
}
should override the Fly() in Bird class when I call Penguin.Fly() because C # call the most specific method.

And someone else replied with a very common (and, unfortunately, not quite correct) answer:

The two keywords are not necessary. However, if you do not use virtual and override, the IDE will give you a warning. This warning means nothing, but being OCD, I cant stand to have any warnings, so I use the 2 keywords

That's a really, really common question, and an equally common response. And I can't blame either of these guys for running into a problem here, because it's one of the easiest errors that you can run into when you're starting to work with C# classes that inherit from other classes.

I've actually seen this exact question many times from new and intermediate C# programmers. Not only that, but I've run into some pretty nasty bugs in real life programming work that stemmed from exactly this problem. So to help out our readers, I wanted to give a little thought to this problem.

I wanted to give you a good exercise to help reinforce this concept, teaching it in a way that's based on how Jenny and I teach many C# concepts throughout Head First C#. So with our Head First C# readers in mind, I came up with a little "Sharpen Your Pencil" problem, just like we have throughout the book:

exercise_sharpen_small.jpg
Take a look at the following code. Can you figure out what the output will be?


using System;
using System.Collections.Generic;

class Program {
     class Jewels {
          public override string ToString() {
               return "Sparkle, sparkle!";
          }
     }
 
     class Owner {
          private object returnedContents;
          public void ReceiveContents(object safeContents) {
               returnedContents = safeContents;
               Console.WriteLine(safeContents);
          }
     }
 
     class Safe {
          class WrongCombinationException : Exception { };
  
          private object contents = new Jewels();
          private string safeCombination = "12345";
          public object Open(string combination) {
               if (combination == safeCombination)
                   return contents;
   
               throw new WrongCombinationException();
          }
          public void PickLock(Locksmith lockpicker) {
               lockpicker.WriteDownCombination(safeCombination);
          }
     }
 
     class Locksmith {
          public void OpenSafe(Safe safe, Owner owner) {
               safe.PickLock(this);
               object safeContents = safe.Open(writtenDownCombination);
               ReturnContents(safeContents, owner);
          }
  
          private string writtenDownCombination = null;
          public void WriteDownCombination(string combination) {
               writtenDownCombination = combination;
          }
  
          public void ReturnContents(object safeContents, Owner owner) {
               owner.ReceiveContents(safeContents);
          }
     }
 
     class JewelThief : Locksmith {
          private List<object> bag = new List<object>();
          public void ReturnContents(object safeContents, Owner owner) {
               bag.Add(safeContents);
               Console.WriteLine(
                  "I'm stealing the contents! {0}", safeContents);
          }
     }
 
     static void Main(string[] args) {
          Owner owner = new Owner();
          Safe safe = new Safe();
  
          Locksmith locksmith = new Locksmith();
          locksmith.OpenSafe(safe, owner);
  
          JewelThief jewelThief = new JewelThief();
          jewelThief.OpenSafe(safe, owner);
     }
}

Before you go on, really take a look through the program and see if you can figure out what it's supposed to do. Here's a hint: it prints two lines to the console. If you want to get the most out of this example, take out a piece of paper (or pop open Notepad) and actually write down what you think the program will output.




The solution's coming up! See if you can figure out what the program's going to do before you look at the answer.


Now run the code, either by pasting it into a new Console Application in Visual Studio, or by saving it to a file (Program.cs) and compiling it with csc.exe. Here's what happens when you run it -- and it's the solution to the exercise:

exercise_sharpen_solution_small.jpg
Take a look at the following code. Can you figure out what the output will be?


C:\src>c:\WINDOWS\Microsoft.NET\Framework\v3.5\csc.exe Program.cs
Microsoft (R) Visual C# 2008 Compiler version 3.5.30729.1
for Microsoft (R) .NET Framework version 3.5
Copyright (C) Microsoft Corporation. All rights reserved.

Program.cs(54,24): warning CS0108: 
'Program.JewelThief.ReturnContents(object, Program.Owner)' hides inherited
member 'Program.Locksmith.ReturnContents(object, Program.Owner)'. 
Use the new keyword if hiding was intended.
Program.cs(47,23): (Location of symbol related to previous warning)

C:\src>Program.exe
Sparkle, sparkle!
Sparkle, sparkle!

Did you expect the second line of the program's output to be different? Maybe something like this:

I'm stealing the contents! Sparkle, sparkle!

So what happened?


Hiding methods versus overriding methods

The reason the JewelThief object acted like a Locksmith object when its ReturnContents() method was called was because of the way the JewelThief class declared its ReturnContents() method. There's a big hint in that warning message you got when you compiled your program:

Program.cs(54,23): warning CS0108: 
'Program.JewelThief.ReturnContents(object, Program.Owner)' hides inherited
member 'Program.Locksmith.ReturnContents(object, Program.Owner)'. 
Use the new keyword if hiding was intended.
Program.cs(47,23): (Location of symbol related to previous warning)

Since the JewelThief class inherits from Locksmith and replaces the ReturnContents() method with its own method, it looks like JewelThief is overriding Locksmith's ReturnContents() method. But that's not actually what's happening. You probably expected JewelThief to override the method (which we'll talk about in a minute), but instead JewelThief is hiding it.

There's a big difference. When a subclass hides the method, it replaces (technically, it "redeclares") a method in its base class that has the same name. So now our subclass really has two different methods that share a name: one that it inherits from its base class, and another brand new one that's defined in its own class.

The JewelThief only hides the ReturnContents() method (as opposed to extending it), and that causes it to act like a Locksmith object whenever it's called like a Locksmith object. JewelThief inherits one version of ReturnContents() from Locksmith, and it defines a second version of it, which means that there are two different methods with the same name. That means your class needs to different ways to call it. And, in fact, it has exactly that:

// The JewelThief subclass hides a method in the Locksmith base class,
// so you can get different behavior from the same object based on the
// reference you use to call it!

// Declaring your JewelThief object as a Locksmith reference causes it to 
// call the base class ReturnContents() method
Locksmith l = new JewelThief();
l.ReturnContents(safeContents, owner);

// Declaring your JewelThief object as a JewelThief reference causes it to 
// call the JewelThief's ReturnContents() method instead, because it hides
// the base class's method of the same name.
JewelThief l = new JewelThief();
l.ReturnContents(safeContents, owner);

That's what that "hides inherited member" warning is about. Normally, when you want to hide a method, you should use the new keyword. So if what you really wanted your JewelThief to hide the ReturnContents() member, you'd declare it like this instead, using the new keyword in the ReturnContents() declaration like this:

class JewelThief : Locksmith {
    private List<object> bag = new List<object>();
    new public void ReturnContents(object safeContents, Owner owner) {
         bag.Add(safeContents);
         Console.WriteLine(
            "I'm stealing the contents! {0}", safeContents);
    }
}

(You can also declare it with the new after the public keyword: public new void ReturnContents(...).)

If you add new to your JewelThief class's ReturnContents() method declaration, that error message will go away. But your program still won't act the way you expect it to! It still calls the ReturnContents() method defined in the Locksmith object. Why? Because the ReturnContents() method is being called from a method defined by the Locksmith class -- specifically, from inside Locksmith.OpenSafe(), even though it's being initiated by a JewelThief object. If JewelThief only hides the ReturnContents() method, its own ReturnContents() will never be called.

So how do you get the JewelThielf's ReturnContents() to be called instead?


Use the override and virtual keywords to inherit behavior

We really want our JewelThief class to always use its own ReturnContents() method, no matter how it's called. This is the way we expect inheritance to work most of the time, and it's called overriding. And it's very easy to get your class to do it. The first thing you need to do is use the override keyword when you declare the ReturnContents() method, like this:

override public void ReturnContents(
           object safeContents, Owner owner) {

(Again, you can also put the override keyword after public -- they'll both compile the same way.)

But that's not everything you need to do. If you just add that override and try to compile, you'll get an error that looks like this:

Program.cs(54,32): error CS0506: 
'Program.JewelThief.ReturnContents(object, Program.Owner)': 
cannot override inherited member 
'Program.Locksmith.ReturnContents(object, Program.Owner)' 
because it is not marked virtual, abstract, or override
Program.cs(47,23): (Location of symbol related to previous error)

I know we don't always like to look at error messages in depth, but sometimes it's useful to take a really close look. In this case, the compiler is actually telling you exactly where the problem is. Program.cs(54,32) tells us that there's a cannot override inherited member on line 54, which in this particular file turns out to be this line:

class JewelThief : Locksmith {
    private List<object> bag = new List<object>();
        override public void ReturnContents(
            object safeContents, Owner owner) {

It's telling us that if we can only override a method in the base class if it's marked virtual or abstract, or if it's overriding another method (which, in turn, is either virtual or abstract or overriding another method, etc.)

So if we want JewelThief's ReturnContents() method to override the method in its base class, then we need to mark that method virtual -- which, incidentally, is what the second half of that error message is telling us, since Locksmith's ReturnContents() method is at line 47, column 23. So here's what it needs to look like:

class Locksmith {
       // ... the rest of the class ...
       virtual public void ReturnContents(
            object safeContents, Owner owner) {

Once you add override to the ReturnContents() declaration in JewelThief and virtual to the ReturnContents() declaration in Locksmith, the program acts the way we'd expect it to, with JewelThief overriding the ReturnContents() method in Locksmith.

C:\src>c:\WINDOWS\Microsoft.NET\Framework\v3.5\csc.exe Program.cs
Microsoft (R) Visual C# 2008 Compiler version 3.5.30729.1
for Microsoft (R) .NET Framework version 3.5
Copyright (C) Microsoft Corporation. All rights reserved.

C:\src>Program.exe
Sparkle, sparkle!
I'm stealing the contents! Sparkle, sparkle!

And that's the behavior we were looking for. When you're working with a subclass that extends a base class, you're much more likely to use overriding than you are to use hiding. So when you see that compiler warning about hiding a method, pay attention to it! Make sure you really want to hide the method, and didn't just forget to use the virtual and override keywords.

You can read more of Andrew's posts at Building Better Software.


You might also be interested in:

News Topics

Recommended for You

Got a Question?