Wednesday, February 23, 2005

Tips with OOP - New, Virtual, and Abstract

[This was originally posted at http://timstall.dotnetdevelopersjournal.com/tips_with_oop__new_virtual_and_abstract.htm]

As I prepare to teach a C# class, I've being looking at ways to explain and clarify certain Object Oriented Programming (OOP) concepts. I find that while a lot of people are familiar with the terms, the specifics always seem confusing. Two questions I often hear are:

  1. What is the difference between using virtual/override and new?
  2. What is the difference between virtual and abstract?

While there are certainly smarter people then myself who have thoroughly explained every inch of OOP, I'll give it my two cents anyway. (For those interested in other resources, I personally like Deitel and Microsoft's C# Spec).

What is the difference between using virtual and new?

The Virtual keyword (used in the base class) lets a method be overridden (by using override in the derived class) such that if you declare an object of a base type, and instantiate it of a derived type, then calling the virtual method will call the derived type's method, not the base type. This is polymorphism.

The new keyword (used in the derived class) lets you hide the implementation of a base method such that when you declare and instantiate an object of the same type, the method of that type is called. There is no polymorphism here.

I think the best way to explain this is via a code sample that shows the different effects of using virtual vs. new. Say you have the following two classes:

    public class MyBase
    {
        public virtual string MyVirtualMethod()
        {
            return "Base";
        }

        public string MyNonVirtualMethod()
        {
            return "Base";
        }
    } //end of sub class

    public class MyDerived : MyBase
    {
        public override string MyVirtualMethod()
        {
            return "Derived";
        }

        public new string MyNonVirtualMethod()
        {
            return "Derived";
        }
    } //end of sub class

This has two classes, MyBase and MyDerived. For illustration, the classes each only have two methods. For comparison, MyBase has one method virtual, and one not. Likewise, MyDerived overrides the virtual method and hides the non-virtual. The following code snippet shows three separate cases. Note that the virtual-new keywords affect the value of MyNonVirtualMethod based on whether the object is declared as type MyBase or MyDerived.

MyBase m1 = new MyDerived();
Console.WriteLine("MyVirtualMethod='" + m1.MyVirtualMethod() + "', MyNonVirtualMethod='" + m1.MyNonVirtualMethod() + "'");
//    Returns: MyVirtualMethod='Derived', MyNonVirtualMethod='Base'

MyDerived md = new MyDerived();
Console.WriteLine("MyVirtualMethod='" + md.MyVirtualMethod() + "', MyNonVirtualMethod='" + md.MyNonVirtualMethod() + "'");
//    Returns: MyVirtualMethod='Derived', MyNonVirtualMethod='Derived'

Note that in the first case, where we declare the object of type MyBase yet instantiate it to type MyDerived, calling MyNonVirtual method is called on the declared type. In the second case, it is called on the Instantiated type.

These concepts are very common when declaring an array of base objects, and then cycling through the array and calling virtual members. A classic example is making an array of Shape objects, calling the GetArea() method on each one, and it correctly returning the area for that shape.

What is the difference between virtual and abstract?

These two keywords are sometimes confused because both can be over-ridden. However, unlike Virtual members, Abstract members have no implementation. As Deitel puts it, "Abstract base classes are too generic to define real world objects" (C# How to Program, pg 392). The Abstract keyword can be applied to either members or the class as a whole. Note that if a class has an abstract member, then that class must itself be abstract (There is no such thing as a "virtual" class).

In the following code snippet below (from Deitel, pg. 394), the abstract class shape has two virtual methods: Area and Double, and one abstract property Name. Note that both virtual members have a concrete implementation. If you create a derived class "Point", and call its Area method, it will return 0.

public abstract class Shape
{
    public virtual double Area()
    {
        return 0;
    }

    public virtual double Volume()
    {
        return 0;
    }

    public abstract string Name
    {
        get;
    }
}

The following table highlights these differences:

 VirtualAbstract
Has implementationYesNo
Scopemembers onlymembers and classes
Can create an instance ofNot Applicable (you can only create instances of classes, not members)No - but you can create an instance of a class that derives from an abstract class. And you can declare a type Abstract class and instantiate that as a derived class.

Common Abstract classes in the .Net framework include System.Xml.XmlNode and System.IO.Stream. Perhaps the most common virtual method is System.Object.ToString().

No comments:

Post a Comment