C# Language virtual, override, new


Example

virtual and override

The virtual keyword allows a method, property, indexer or event to be overridden by derived classes and present polymorphic behavior. (Members are non-virtual by default in C#)

public class BaseClass
{
    public virtual void Foo()
    {
        Console.WriteLine("Foo from BaseClass");
    }
}

In order to override a member, the override keyword is used in the derived classes. (Note the signature of the members must be identical)

public class DerivedClass: BaseClass
{
    public override void Foo()
    {
        Console.WriteLine("Foo from DerivedClass");
    }
}

The polymorphic behavior of virtual members means that when invoked, the actual member being executed is determined at runtime instead of at compile time. The overriding member in the most derived class the particular object is an instance of will be the one executed.

In short, object can be declared of type BaseClass at compile time but if at runtime it is an instance of DerivedClass then the overridden member will be executed:

BaseClass obj1 = new BaseClass();
obj1.Foo(); //Outputs "Foo from BaseClass"

obj1 = new DerivedClass();
obj1.Foo(); //Outputs "Foo from DerivedClass"    

Overriding a method is optional:

public class SecondDerivedClass: DerivedClass {}

var obj1 = new SecondDerivedClass();
obj1.Foo(); //Outputs "Foo from DerivedClass"    

new

Since only members defined as virtual are overridable and polymorphic, a derived class redefining a non virtual member might lead to unexpected results.

public class BaseClass
{
    public void Foo()
    {
        Console.WriteLine("Foo from BaseClass");
    }
}

public class DerivedClass: BaseClass
{
    public void Foo()
    {
        Console.WriteLine("Foo from DerivedClass");
    }
}

BaseClass obj1 = new BaseClass();
obj1.Foo(); //Outputs "Foo from BaseClass"

obj1 = new DerivedClass();
obj1.Foo(); //Outputs "Foo from BaseClass" too!    

When this happens, the member executed is always determined at compile time based on the type of the object.

  • If the object is declared of type BaseClass (even if at runtime is of a derived class) then the method of BaseClass is executed
  • If the object is declared of type DerivedClass then the method of DerivedClass is executed.

This is usually an accident (When a member is added to the base type after an identical one was added to the derived type) and a compiler warning CS0108 is generated in those scenarios.

If it was intentional, then the new keyword is used to suppress the compiler warning (And inform other developers of your intentions!). the behavior remains the same, the new keyword just suppresses the compiler warning.

public class BaseClass
{
    public void Foo()
    {
        Console.WriteLine("Foo from BaseClass");
    }
}

public class DerivedClass: BaseClass
{
    public new void Foo()
    {
        Console.WriteLine("Foo from DerivedClass");
    }
}

BaseClass obj1 = new BaseClass();
obj1.Foo(); //Outputs "Foo from BaseClass"

obj1 = new DerivedClass();
obj1.Foo(); //Outputs "Foo from BaseClass" too! 

The usage of override is not optional

Unlike in C++, the usage of the override keyword is not optional:

public class A
{
    public virtual void Foo()
    {
    }
}

public class B : A
{
    public void Foo() // Generates CS0108
    {
    }
}

The above example also causes warning CS0108, because B.Foo() is not automatically overriding A.Foo(). Add override when the intention is to override the base class and cause polymorphic behavior, add new when you want non-polymorphic behavior and resolve the call using the static type. The latter should be used with caution, as it may cause severe confusion.

The following code even results in an error:

public class A
{
    public void Foo()
    {
    }
}

public class B : A
{
    public override void Foo() // Error: Nothing to override
    {
    }
}

Derived classes can introduce polymorphism

The following code is perfectly valid (although rare):

    public class A
    {
        public void Foo()
        {
            Console.WriteLine("A");
        }
    }

    public class B : A
    {
        public new virtual void Foo() 
        {
            Console.WriteLine("B");
        }
    }

Now all objects with a static reference of B (and its derivatives) use polymorphism to resolve Foo(), while references of A use A.Foo().

A a = new A();
a.Foo(); // Prints "A";
a = new B();
a.Foo(); // Prints "A";
B b = new B();
b.Foo(); // Prints "B";

Virtual methods cannot be private

The C# compiler is strict in preventing senseless constructs. Methods marked as virtual cannot be private. Because a private method cannot be seen from a derived type, it couldn't be overwritten either. This fails to compile:

public class A
{
    private virtual void Foo() // Error: virtual methods cannot be private
    {
    }
}