C# Polymorphism Introduction


This entry is part 1 of 5 in the series C# Polymorphism

The post C# Introduction lists all of the C# series of posts we have at this site.

Polymorphism is the third pillar of OOP.

One consequence of inheritance is that classes deriving from a base class have an overlap in the methods and properties that they expose. Because of this, it is often possible to treat objects instantiated from classes with a base type in common using identical syntax. For example, if a base class called Animal has a method called EatFood(), then the syntax for calling this method from the derived classes Cow and Chicken will be similar. First, let’s look at Animal.

public class Animal { 
    public virtual void eatFood()
    {
        Console.WriteLine("animal eat food");
    }
}

Here is our Dog, which derives from Animal. We could also say that Dog extends Animal, especially if we were a Java programmer, and it would mean exactly the same thing. Another way of saying it is that Animal is the superclass and Dog is the base class. In the code below we can say that the colon means “inherits from“. Our dog has a method called eatFood() and its superclass also has a method with exactly the same name. The dog class’ eatFood() method overrides the parent’s eatFood() without affecting the parent class Animal in any way.

public class Dog : Animal
{
    public void makeSound()
    {
        Console.WriteLine("Bark");
    }
    public override void eatFood()
    {
        Console.WriteLine("dog eat food");
    }
}

Now let’s look into the client code. The client in our case is the code in the Main method because this is a C# console app. Assume that we also have Cows and Chickens and have code very similar to the above Dog.

Cow myCow = new Cow();
Chicken myChicken = new Chicken();
myCow.eatFood();
myChicken.eatFood();

Polymorphism takes this a step further. You can assign a variable that is of a derived type (myCow) to a variable of one the base types (myAnimal), as shown below. Is myAnimal an Animal or a Cow? The code seems to indicate that it is an Animal because the type is Animal. When we want to create an integer we say: int myNumber = 7, for example, making myNumber an integer type. Our Animal however starts to behave like a cow in the code example after that when we start to call methods of the base class Cow, not the apparent actual class Animal.

Animal myAnimal = myCow;

No casting is required for this. You can then call methods of the base class through this variable:

myAnimal.eatFood();

This results in the implementation of eatFood() in the derived/base class being called. Note that you can’t call methods defined on the derived class in the same way. The following code won’t work: myAnimal.Moo(). Moo() is defined in the base class Cow.

However, you can cast ((Cow)) a base type variable (mtAnimal) into a derived class variable (myNewCow) and call the method of the derived class (Moo) that way:

Cow myNewCow = (Cow)myAnimal;
myNewCow.Moo();

This casting causes an exception to be raised if the type of the original variable was anything other than Cow or a class derived from Cow. Remember that in C# all classes derive from the base class object at the root of their inheritance hierarchies. It is therefore possible to treat all objects as instances of the class object.

Arrays or Lists of Animals

You could create an array of animals that is really an array of various base classes, like dogs and cats and chickens. We could have an array of Animals that has a dog, a cat, a chicken, and another dog. You’d still have access to the base class methods. When you call eatFood you get the method of the base class-specific animal.

Passing Animals that are Really Dogs

You could have a method that takes an Animal and passes in an Animal to it. That animal was originally a Dog. Inside that method you could call a method of the derived class Dog, such as eatFood(), and you will see that the dog is eating food.

Casting

In this example we take a Dog and cast it into an Animal. We still have access to the dog’s eatFood() method. However, the Animal class only knows of methods in the Animal class. If you had a method called makeSound() in the Dog class that was not also in the Animal class, you would not be able to call makeSound(). The compiler will complain. However, we can use casting. You’ll need to use brackets to be able to call makeSound().

Dog myDog = new Dog();
Animal animaldog = (Animal)myDog;  // myDog is of type Dog
animaldog.eatFood();  // dog eat food
((Dog)animaldog).makeSound(); // Bark

YouTube Video by Derek Banas

If you like to learn by watching videos, have a look at the video by Derek Banas called Design Patterns Video Tutorial 2. This video is not about design patterns. Derek has a series of videos on design patterns and he starts the series with two refresher videos that cover the basics of OOP. His second video starts off with polymorphism. He uses the language Java to write his code.

Series NavigationC# Classes Polymorphism 2 >>