C# Polymorphism Tutorial

In this tutorial we learn how polymorphism allows us to override members of a parent class with our own functionality.

We cover abstract classes without implementation and sealed classes that restrict inheritance.

Here's a table of contents of what you'll learn in this lesson:
(click on a link to skip to its section)

Let's jump right in.

What is polymorphism

Another one of the three core principles, or pillars, in any object oriented program is polymorphism. The word polymorphism means having many forms.

Polymorphism, in object oriented programming, means we can override members of a parent class from inside a child class to contain custom functionality.

How to override a class member

Polymorphism enables a child class to define its own version of a member that’s also defined by its parent class. We change the implementation of an inherited member.

To do this we create a method in the child class with exactly the same name as the one in the parent class.

We must also mark the method that will be overridden in the parent class as virtual , and the method that will override it in the child class as override .

Syntax:
class ParentClass
{
    // mark member to be changed
    virtual type Identifier()
    {
        // default implementation
    }
}

class SubClass : ParentClass
{
    // change implementation of marked
    // member with the same identifier
    override type Identifier()
    {
        // new implementation
    }
}
Example:
using System;

namespace Classes
{
    class Program
    {
        static void Main(string[] args)
        {
            Coupe coupe = new Coupe();

            coupe.Drive();

            Console.ReadLine();
        }
    }

    public class Car
    {
        public virtual void Drive()
        {
            Console.WriteLine("Driving");
        }
    }

    public class Coupe : Car
    {
        public override void Drive()
        {
            Console.WriteLine("Driving fast");
        }
    }
}

In the example above, we marked the Drive() method in the Car class as virtual. That means, we can override its functionality in any child class, which we did in the Coupe child class.

We don’t have to override the virtual method. If we don’t override it, the virtual method will be inherited as it would normally.

Abstract classes

The abstract modifier indicates that a class or a member is missing its implementation. This is similar to an interface, which we look at in the Interfaces section.

An abstract method doesn’t have a code block, instead it looks like a method call. We don’t provide the code block in the parent class, but we must provide it in the child class, we have to override an abstract member.

Syntax:
abstract class ParentClass
{
    abstract type Identifier();
}

class SubClass : ParentClass
{
    override type Identifier()
    {
        // set implementation
    }
}

A class that contains an abstract member, must be marked as abstract too and cannot be instantiated.

Example:
using System;

namespace Classes
{
    class Program
    {
        static void Main(string[] args)
        {
            Coupe coupe = new Coupe();
            coupe.Drive();

            Console.ReadLine();
        }
    }

    public abstract class Car
    {
        public abstract void Drive();
    }

    public class Coupe : Car
    {
        public override void Drive()
        {
            Console.WriteLine("Driving fast");
        }
    }
}

In the example above, we marked the Car class and its Drive() method as abstract. The child class Coupe then had to override the Drive() method.

Why use abstract

Because abstract classes are so strict, we can provide common behavior, while forcing other developers to follow our design.

In our Car example, we force a developer to provide a Drive() method for whichever car they’re designing. If we didn’t, they might make it fly, and before we know it someone is coming down our chimney in search of milk and cookies!

Sealed classes

Sealed classes are the opposite of abstract classes. The sealed modifier prevents derivation of classes and overriding of methods.

If the sealed modifier is applied to a class, it prevents inheritance of the class.

Syntax:
sealed class Identifier
{
    // class body
}
Example:
using System;

namespace Classes
{
    class Program
    {
        static void Main(string[] args) { }
    }

    public sealed class Car
    {
        public void Drive()
        {
            Console.WriteLine("Driving");
        }
    }

    // compiler error: cannot derive from sealed type
    public class Coupe : Car { }
}

In the example above, we sealed the Car class, so its child class Coupe cannot derive from it and the compiler will generate an error.

If the sealed modifier is applied to a method, it prevents the method from being overridden.

Syntax:
class ParentClass
{
    public virtual funcType funcIdentifier(parameterList)
    {
        // function body
    }
}

class ChildClass : ParentClass
{
    public sealed override funcType funcIdentifier(parameterList)
    {
        // function body
    }
}

The sealed modifier can only be applied to a method that is overriding a method on the parent class.

Example:
using System;

namespace Classes
{
    class Program
    {
        static void Main(string[] args)
        {
            Coupe coupe = new Coupe();

            coupe.Drive();

            Console.ReadLine();
        }
    }

    public class Car
    {
        public virtual void Drive()
        {
            Console.WriteLine("Driving");
        }
    }

    public class Coupe : Car
    {
        public sealed override void Drive()
        {
            Console.WriteLine("Driving fast");
        }
    }

    public class Twoseater : Coupe
    {
        // compiler error: cannot override inherited
        // member because it is sealed
        public override void Drive() { }
    }
}

In the example above, we sealed the override on the Coupe child class. When we try to override it in the TwoSeater class, the compiler raises an error.

Why use sealed

The MSDN documentation states that sealed classes are slightly faster because of run-time optimizations.

However, sealed is one of those features that is hardly ever used because it can mess up the inheritance hierarchy.

Summary: Points to remember

  • Polymorphism is a big scary word that simply means we override members of a parent class from within a child class.
  • An abstract method doesn’t have an implementation (i.e a body). The inheriting class must override the method.
    • If a method is marked as abstract, the class itself must be marked as abstract as well.
    • An abstract method definition looks like a normal method call.
  • The sealed modifier blocks a class from being inherited.
    • If the sealed modifier is applied to a method, it blocks the method from being overridden.