C# Classes Theory Part 4 Polymorphism Part 2


Let’s go back to the essence of polymorphism by looking at another text book called C#: A Beginner’s Tutorial, Second Edition by Jayden Ky. Consider chapter 11. This section offers a more complete explanation of polymorphism than the previous post.

namespace Polymorphism
{
    class Program
    {
        static void Main(string[] args)
        {
            B b = new B();
            A a = b;
            WriteLine(a.GetType().ToString());  // Polymorphism.B
            // What will be displayed when the line below executes?
            // The answer is B, not A, provided that the Play 
            // method of B can override the Play method of A as
            // per the keywords virtual and override.
            //
            WriteLine(a.Play());  // "Class B Play"
            // a.Stop() will display Stop! at the console.
            // Why does b.Stop()  do the same?
            WriteLine(b.Stop());
            ReadKey();
        }
    }
    public class A  // parent class
    {
        public virtual string Play()  {
            return "Class A Play";
        }
        public string Stop()
        {
            return "Stop!";
        }
    }
    public class B : A  // B inherits from A
    {
        public override string Play() {
            return "Class B Play";
        }
    }
}

In C# and other OOP languages, it is legal to assign to a reference variable an object whose type is different from the variable type, if certain conditions are met. In essence, if you have a reference variable a whose type is A, it is legal to assign an object of type B, like this

A a = b;

provided one of the following conditions is met.
A is a class and B is a subclass of A.
A is an interface and B or one of its parents implements A.
This is called upcasting.

When you assign a an instance of B like in the preceding code, a is of type A. This means, you cannot call a method in B that is not defined in A. However, if you print the value of a.GetType().ToString(), you’ll get “B” and not “A.” So, what does this mean? At compile time, the type of a is A, so the compiler will not allow you to call a method in B that is not defined in A. On the other hand, at runtime the type of a is B, as proven by the return value of a.GetType().ToString().

Now, here comes the essence of polymorphism. If B overrides a method (say, a method named Play) in A, calling a.Play() will cause the implementation of Play in B (and not in A) to be invoked. Polymorphism enables an object (in this example, the one referenced by a) to determine which method implementation to choose (either the one in A or the one in B) when a method is called. Polymorphism dictates that the implementation in the runtime object be invoked.

What if you call another method in a (say, a method called Stop) and the method is not implemented in B? The CLR will be smart enough to know this and look into the inheritance hierarchy of B. B, as it happens, must be a subclass of A or, if A is an interface, a subclass of another class that implements A. Otherwise, the code would not have compiled. Having figured this out, the CLR will climb the ladder of the class hierarchy and find the implementation of Stop and execute it.

Now, there is more sense in the definition of polymorphism: Polymorphism is an OOP feature that enables an object to determine which method implementation to invoke upon receiving a method call.

Go back to Polymorphism Part 1
Ahead to Polymorphism Part 3

Leave a comment

Your email address will not be published. Required fields are marked *