o7planning

Inheritance and polymorphism in C#

  1. Class, object and constructor
  2. Inheritance in CSharp
  3. Polymorphism in CSharp

1. Class, object and constructor

You need to understand explicitly about class, constructor and instance before starting to learn inheritance in C#. We see class Person, describes a person with the relevant information.
Person.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace InheritancePolymorphism
{
    class Person
    {
        // Name of person
        public String Name;

        // Year of Birth
        public int BornYear;

        // Place of Birth
        public String PlaceOfBirth;

        // This Constructor has 3 parameters. 
        // The aim to initialize the value for fields of Person.
        // Specify the name, year of birth, place of birth.
        public Person(String Name, int BornYear, String PlaceOfBirth)
        {
            this.Name = Name;
            this.BornYear = BornYear;
            this.PlaceOfBirth = PlaceOfBirth;
        } 
        // This Constructor have 2 parameters. 
        // Purpose initialize for two fields (name & Born year) of Person.
        // PlaceOfBirth not be initialized.
        public Person(String Name, int BornYear)
        {
            this.Name = Name;
            this.BornYear = BornYear;
        } 
    }
}
PersonDemo.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace InheritancePolymorphism
{
    class PersonDemo
    { 
        static void Main(string[] args)
        { 
            // Instance: Thomas Edison.
            // Created by Constructor has 2 parameters of the Person class.
            Person edison = new Person("Thomas Edison", 1847);

            Console.WriteLine("Info:");
            Console.WriteLine("Name: " + edison.Name);
            Console.WriteLine("Born Year: " + edison.BornYear);
            Console.WriteLine("Place Of Birth: " + edison.PlaceOfBirth);

            // Instance: Bill Gates.
            // Created by Constructor has 3 parameters of the Person class.
            Person billGates = new Person("Bill Gate", 1955, "Seattle, Washington"); 
            Console.WriteLine("-----------------------------------"); 
            Console.WriteLine("Info:");
            Console.WriteLine("Name: " + billGates.Name);
            Console.WriteLine("Born Year: " + billGates.BornYear);
            Console.WriteLine("Place Of Birth: " + billGates.PlaceOfBirth); 
            Console.ReadLine();
        }
    }
}
Running PersonDemo:
Info:
Name: Thomas Edison
Born Year: 1847
Place Of Birth:
-----------------------------------
Info:
Name: Bill Gate
Born Year: 1955
Place Of Birth: Seattle, Washington
Distinguishing Class, constructor and instance:
Person simulate a class of people, it is something abstract, but it has information, in the example above, information is the name, year of birth, place of birth.
Constructor.
  • Constructor always have the same name as the class
  • One class has one or more constructors.
  • Constructor with or without parameters, no parameters constructor called default constructor.
  • Constructor using for create a instance of class.
Thus Person class (Descript people class) is abstract, but when it points out to you or me,they are 2 instances of Person class. And constructors are special methods to create instances, constructor will assign values to the fields of class..
These are illustrations of how to assign value for field of class, when you create the instance from constructor.

2. Inheritance in CSharp

We need a few classes to participate in examples.
  • Animal: Class simulate an animal.
  • Duck: Subclass of Animal.
  • Cat: Subclass of Animal.
  • Mouse: Subclass of Animal.
As already said earlier, constructor of class used to create an object (instance), and assign the value for the fields.
Constructor of subclasses always called to a constructor of parent class to initialize value for the fields in the parent class, then it start assign value for its fields.
Example:
Animal.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace InheritancePolymorphism
{
    public abstract class Animal
    {
        // This is Name field.
        // for example, Tom cat, Jerry mouse.
        public string Name;

        // Default constructor.
        public Animal()
        {
            Console.WriteLine("- Animal()");
        } 
        public Animal(string Name)
        {
            // Assign a value to the Name field.
            this.Name = Name;
            Console.WriteLine("- Animal(string)");
        } 
        // Move(): Animal Move.
        // Virtual: Allows the subclass to override this method.
        public virtual void Move()
        {
            Console.WriteLine("Animal Move");
        } 
        public void Sleep()
        {
            Console.WriteLine("Sleep");
        } 
    }
}
Cat is the class that inherits from the Animal class, it also has its fields.
Cat.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace InheritancePolymorphism
{
    public class Cat : Animal
    { 
        public int Age;
        public int Height; 
        // This is a Constructor with 3 parameters.
        // Using :base(name) to call constructor of parent: Animal(string).
        // The fields of superclass will be assigned values.
        // Then the fields of this class is assigned values.
        public Cat(string name, int Age, int Height)
            : base(name)
        {
            this.Age = Age;
            this.Height = Height;
            Console.WriteLine("- Cat(string,int,int)");
        } 
        // This constructor call to default constructor of superclass.
        public Cat(int Age, int Height)
            : base()
        {
            this.Age = Age;
            this.Height = Height;
            Console.WriteLine("- Cat(int,int)");
        } 
        public void Say()
        {
            Console.WriteLine("Meo");
        } 
        // Override method in parent class.
        // Rewrite this method,
        // to accurately describe the behavior of the cat.
        public override void Move()
        {
            Console.WriteLine("Cat Move ...");
        }
    }
}
CatTest.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace InheritancePolymorphism
{
    class CatTest
    {
        static void Main(string[] args)
        { 
            Console.WriteLine("Create Cat object from Cat(string,int,int)"); 
            // Create a Cat object via Constructor with 3 parameters:
            // Name of Animal assigned the value "Tom".
            // Age of Cat assigned the value 3
            // Height of Cat assigned the value 20.
            Cat tom = new Cat("Tom",3, 20); 
            Console.WriteLine("------"); 
            Console.WriteLine("Name = {0}", tom.Name);
            Console.WriteLine("Age = {0}", tom.Age);
            Console.WriteLine("Height = {0}", tom.Height);

            Console.WriteLine("------");

            // Call method inherited from Animal
            tom.Sleep();

            // Call Say() method (of Cat)
            tom.Say();  
            Console.ReadLine();
        }
    }
}
Result of running CatTest:
Create Cat object from Cat(string,int,int)
- Animal(string)
- Cat(string,int,int)
------
Name = Tom
Age = 3
Height = 20
------
Sleep
Meo
What's happened when you create an object from constructor . How does it call up a constructor of the parent class? Please see the illustration below:
With the above illustration you see that, constructor of parent class is always called before constructor of subclass, it will assign values to the fields of the parent class, then the fields of the subclass.
When you write a constructor which is not explicitly declared that it is based from which constructor of parent class, CSharp is understood that such constructor is based from default constructor of parent class.
// This constructor does not specify the constructor of the parent class that is based on.
public Cat(int Age, int Height)
{

} 
// It would be equivalent to:
public Cat(int Age, int Height) : base()
{

}
A constructor can call another constructor in the same class using :this.
private int Weight;

// Default Constructor (has no parameter)
// It call to Mouse(int) constructor.
public Mouse()    : this(100)
{
} 
// This is a Constructor has one parameter.
// Not specified :base
// (Its based from default constructor of parent class).
public Mouse(int Weight)
{            
   this.Weight = Weight;
}
Mouse.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace InheritancePolymorphism
{
    public class Mouse : Animal
    { 
        private int Weight;

        // Default constructor (Without parameter).
        // Call to Mouse(int)
        public Mouse()
            : this(100)
        {
        } 
        // This Constructor has one parameter.
        // And not specified 'base'.
        // This constructor based from default Constructor of parent class.
        public Mouse(int Weight)
        {            
            this.Weight = Weight;
        } 
        // This Constructor has 2 parameters.
        public Mouse(String name, int Weight)
            : base(name)
        {
            this.Weight = Weight;
        } 
        public int GetWeight()
        {
            return Weight;
        } 
        public void SetWeight(int Weight)
        {
            this.Weight = Weight;
        } 
    }
}
You can use "is" operator to check an object is the type of a certain Type or not. See the example below:
IsOperatorDemo.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace InheritancePolymorphism
{
    class IsOperatorDemo
    {
        static void Main(string[] args)
        {
            // Create Animal object.
            // Animal is abstract class,
            // so can not create objects from the constructor of Animal.
            Animal tom = new Cat("Tom", 3, 20); 
            Console.WriteLine("Animal Sleep:");

            // Call Sleep() method of Animal
            tom.Sleep();

            // Using the operator 'is' to check the type of an object
            bool isMouse = tom is Mouse;// false 
            Console.WriteLine("Tom is mouse? " + isMouse);

            bool isCat = tom is Cat; // true
            Console.WriteLine("Tom is cat? " + isCat);

            bool isAnimal = tom is Animal; // true
            Console.WriteLine("Tom is animal? " + isAnimal); 
            Console.ReadLine();
        }
    }
}
Running the example:
- Animal(string)
- Cat(string,int,int)
Animal Sleep:
Sleep
Tom is mouse: False
Tom is cat? True
Tom is animal? True
Cast in CSharp.
CastDemo.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace InheritancePolymorphism
{
    class CastDemo
    {
        static void Main(string[] args)
        {
            // Call method, it returns a random Animal.
            Animal animal = GetRandomAnimal();

            if (animal is Cat)
            {
                Console.WriteLine("Your animal is Cat");

                // Cast to Cat object
                Cat cat = (Cat)animal;

                // And access Height of Cat
                Console.WriteLine("Cat height: " + cat.Height);
            }
            else if (animal is Mouse)
            {
                Console.WriteLine("Your animal is Mouse");

                // Cast to Mouse object.
                Mouse mouse = (Mouse)animal;

                // Call a method of Mouse
                Console.WriteLine("Mouse weight: " + mouse.GetWeight());
            }

            Console.ReadLine();
        }

        // The method returns random Animal.
        public static Animal GetRandomAnimal()
        {
            // return random number between 0 and 9 (0,...9)
            int random = new Random().Next(0, 10);

            Console.WriteLine("random = " + random);

            Animal animal = null;
            if (random < 5)
            {
                Console.WriteLine("Create a Cat");
                animal = new Cat("Tom", 3, 20);
            }
            else
            {
                Console.WriteLine("Create a Mouse");
                animal = new Mouse("Jerry", 5);
            }
            return animal;
        }
    }
}
Running the example:
random = 1
Create a Cat
- Animal(string)
- Cat(string,int,int)
Your animal is Cat
Cat height: 20

3. Polymorphism in CSharp

The word polymorphism means having many forms. In object-oriented programming paradigm, polymorphism is often expressed as 'one interface, multiple functions'.

Polymorphism can be static or dynamic. In static polymorphism, the response to a function is determined at the compile time. In dynamic polymorphism, it is decided at run-time.
You have a cat Asian Cat, you can call it is a Cat or call it is an Animal which is an aspect of the polymorphism.

Or another example: On your resume records that you're an Asian man, while you actually are a Vietnamese.

The example below shows you how to behave between declaring and reality
PolymorphismCatDemo.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace InheritancePolymorphism
{
    class PolymorphismCatDemo
    {
        static void Main(string[] args)
        {
            // Declare an Animal object
            // By creating it by Constructor of the Cat class.
            // ** Instance 'tom' declared as Animal
            // So it can only call Animal's methods.
            Animal tom = new Cat("Tom", 3, 20); 

            // Call Sleep() method.
            tom.Sleep();

            // - Move() defined in Animal class
            // - Move() is overridden in Cat class.
            // Actual 'tom' is Cat, although it is declared Animial.
            // ==> It will call the Move() method defined in the Cat class.
            tom.Move(); // ==> Cat Move.  
            Console.ReadLine();
        }
    }
}
- Animal(string)
- Cat(string,int,int)
Sleep
Cat Move ...
You have two ways to rewrite a method defined in the superclass, using the override keyword or new. And they are very different. Please see the illustration below:
Duck.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace InheritancePolymorphism
{
   class Duck : Animal
   {

       public Duck(string name)
           : base(name)
       {
           Console.WriteLine("- Duck(string)");
       }


       public new void Move()
       {
           Console.WriteLine("Duck Move..");
       }
   }
}
InheritanceDuckDemo.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace InheritancePolymorphism
{
    class InheritanceDuckDemo
    {
        static void Main(string[] args)
        {
            // Declare an Animal object.
            // But create it via the Constructor of the Duck class.  
            Animal donald = new Duck("Donald");

            // Call Sleep() method (Defined in Animal).
            donald.Sleep();

            // - Move() defined in Animal class.
            // - Move() is "rewritten" with the keyword 'new' in the Duck class.
            //  ('new' Move() is only used for objects declared as Duck or subclass of Duck).
            // 'donald' được khai báo là 'Animal', không phải 'Duck'.
            donald.Move(); // ==> Animal Move.  
            Console.ReadLine();
        }
    }
}
Running the example:
- Animal(string)
- Duck(string)
Sleep
Animal Move