Héritage et polymorphisme en C#

View more Tutorials:

1- Introduction

L'héritage et le polymorphisme - c'est un concept très important en CSharp. Vous devez le comprendre mieux si vous voulez l'apprendre.

2- La classe, l'objet et le constructeur

Vous devez comprendre explicitement la classe, le constructeur (constructor) et l'objet avant de commencer à apprendre l'héritage en CSharp. Nous voyons la classe Person, décrit une personne avec les informations pertinentes.
Person.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace InheritancePolymorphism
{
    class Person
    {
        // Le champ name - nom de la personne
        public String Name;

        // Le champ bornYear - l'année de naissance
        public int BornYear;

        // Lieu de naissance
        public String PlaceOfBirth;

        // Ce constructeur a 3 paramètres.
        // L'objectif à initialiser la valeur du champs de Person.
        // Précisez le nom, l'année de naissance et le lieu de naissance.
        public Person(String Name, int BornYear, String PlaceOfBirth)
        {
            this.Name = Name;
            this.BornYear = BornYear;
            this.PlaceOfBirth = PlaceOfBirth;
        }

        // Ce constructeur a 2 paramètres.
        // Le but  d'initialiser 2 champs (nom et année de naissance) de Person.
        // Le lieu de naissance n'est pas initialisé.
        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)
        {

            // Objet : Thomas Edison.
            // Créé par Constructeur ayant 2 paramètre de la classe Person.
            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);

            // Objet: Bill Gates
            // Créé par Constructeur ayant 3 paramètre de la classe Person.
            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();
        }
    }
}
L'exécution de la classe  PersonDemo:

Différencier la classe, le constructeur et l'objet :

La classe  Person simule une classe de personnes, c'est quelque chose abstraite, mais elle a des informations. Dans l'exemple ci-dessus, l'information est le nom, l'année de naissance, le lieu de naissance.
Constructor.
  • Le constructeur a toujours le même nom de celui de la classe.
  • Une classe a un ou plusieurs Constructeur(s).
  • Le Constructeur avec ou sans paramètres, aucun constructeur de paramètres a appelé constructeur par défaut.
  • Le Constructeur utilise pour créer un objet de la classe.
Donc la classe  Person (Description de la classe personne) est abstraite, mais quand elle indique à vous ou à moi, ce sont 2 instances de la classe Person. Et les constructeurs sont des méthodes spéciales pour créer des instances, le constructeur affectera des valeurs aux champs (field) de la classe.
Ce sont des illustrations de la façon d'affecter une valeur au champ (field) de classe, lorsque vous créez l'instance à partir du constructeur.

3- Héritage dans 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.
Comme déjà dit plus haut, le constructeur de classe sert à créer un objet (instance), et affecter la valeur pour les champs (field).
Le constructeur des sous-classes ont toujours appelé par un constructeur de la classe parente pour initialiser la valeur des champs de la classe parente, puis commence à affectuer une valeur à ses champs.
Exemple :
Animal.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace InheritancePolymorphism
{
    public abstract class Animal
    {
        // Ceci est le champ Name (Nom).
        // par exemple Chat Tom, Souri Jerry.
        public string Name;

        // Le constructeur par défaut.
        public Animal()
        {
            Console.WriteLine("- Animal()");
        }

        public Animal(string Name)
        {
            // Affectuez la valeur au champ Name.
            this.Name = Name;
            Console.WriteLine("- Animal(string)");
        }

        // Move(): Animaux se  déplacent.
        // virtual: Permet la sous- classe de remplacer (override) cette méthode.
        public virtual void Move()
        {
            Console.WriteLine("Animal Move");
        }

        public void Sleep()
        {
            Console.WriteLine("Sleep");
        }

    }
}
Cat est la sous- classe qui hérite de la classe  Animal, elle a également son champ.
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;

        // Ceci est un Constructeur ayant 3 paramètres de la classe Cat.
        // Utilisant :base(name) pour appeler le Constructeur de la classe mère : Animal(string).
        // Les champs de la super- classe seront affectés des valeurs.
        // Puis ces champs de cette classes seront affectés des valeurs.
        public Cat(string name, int Age, int Height)
            : base(name)
        {
            this.Age = Age;
            this.Height = Height;
            Console.WriteLine("- Cat(string,int,int)");
        }

        // Ce constructeur appelle le constructeur par défaut (qui n'a pas de paramètre) de super-classe.
        public Cat(int Age, int Height)
            : base()
        {
            this.Age = Age;
            this.Height = Height;
            Console.WriteLine("- Cat(int,int)");
        }

        public void Say()
        {
            Console.WriteLine("Meo");
        }

        // Remplacez la méthode Move() de super-classe (Animal).
        // Re-écrivez cette méthode,
        // pour décrire avec précision le comportement du chat.
        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)");

            // Créez un objet Cat via un constructeur avec 3 paramètres.
            // Le champ Name de la classe Animal sera affecté la valeur "Tom".
            // Le champ Age của Cat sera affecté la valeur 3
            // Le champ Height của Cat sera affecté la valeur 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("------");

            // Appelez la méthode héritée de la classe Animal.
            tom.Sleep();

            // Appelez la méthode Say() (de la classe Cat)
            tom.Say();


            Console.ReadLine();
        }
    }
}
Le résultat de l'exécution  CatTest:
Que se passe-t-il lorsque vous créez un objet à partir du constructeur. Comment appelle-t-il un constructeur de la classe mère? S'il vous plaît voyez l'illustration ci-dessous :
Avec l'illustration ci-dessus vous voyez que le constructeur de la classe mère est toujours appelé avant le constructeur de la sous-classe, il va affecter des valeurs aux champs de la classe mère, puis aux champs de la sous-classe.
Lorsque vous écrivez un constructeur qui n'est pas explicitement déclaré qu'il est basé (base) sur le constructeur de la classe mère, CSharp est entendu que ce constructeur est basé sur le constructeur par défaut de la classe mère.
// Ce constructor ne précise pas sur quel constructeur de la classe mère qu'il est basé (base).
public Cat(int Age, int Height)
{

}

// Il est équivalent à :
public Cat(int Age, int Height) : base()
{

}
Un constructeur peut appeler un autre constructeur dans la même classe en utilisant: this.
private int Weight;

// Le constructeur par défaut (N'a pas de paramètre).
// Il appelle au constructeur Mouse(int).
public Mouse()    : this(100)
{
}

// Ceci est un constructeur âynt un paramètre.
// Non précisé :base
// Il est basé (base) sur le Constructeur par défaut de la classe mère.
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;

        // Constructeur par défaut (Sans paramètre).
        // Appelle au Mouse(int)
        public Mouse()
            : this(100)
        {
        }

        // Ce constructeur a 1 paramètre.
        // Non précisé :base
        // Ce constructeur est basé (base) sur le constructeur par défaut de la classe mère.
        public Mouse(int Weight)
        {            
            this.Weight = Weight;
        }

        // Ce constructeur a 2 paramètres.
        public Mouse(String name, int Weight)
            : base(name)
        {
            this.Weight = Weight;
        }

        public int GetWeight()
        {
            return Weight;
        }

        public void SetWeight(int Weight)
        {
            this.Weight = Weight;
        }

 
    }
}
Vous pouvez utiliser l'opérateur 'is' pour vérifier qu'un objet est le type d'un certain type de la classe ou non. Voyez l'exemple ci-dessous :
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)
        {
            // Créez un objet Animal.
            // Animal est une classe abstraite,
            // Donc vous ne pouvez pas créer l'objet via le Constructeur de Animal.
            Animal tom = new Cat("Tom", 3, 20);

            Console.WriteLine("Animal Sleep:");

            // Appelez la méthode Sleep() de Animal
            tom.Sleep();

            // Utilisez l'opérateur 'is' pour vérifier si
            // un objet est le type d'un objet.
            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();
        }
    }
}
Exécution de l'exemple :

Le cast (cast) dans 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)
        {
            // Appelez la méthode, elle renvoie un animal aléatoire.
            Animal animal = GetRandomAnimal();

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

                // Cast (cast) en objet Cat.
                Cat cat = (Cat)animal;

                // Et accédez au champ Height de l'objet Cat.
                Console.WriteLine("Cat height: " + cat.Height);
            }
            else if (animal is Mouse)
            {
                Console.WriteLine("Your animal is Mouse");

                // Cast (cast) en objet Mouse.
                Mouse mouse = (Mouse)animal;

                // Appelez une méthde de la classe Mouse.
                Console.WriteLine("Mouse weight: " + mouse.GetWeight());
            }

            Console.ReadLine();
        }

        // La méthode renvoie un aminal aléatoire.
        public static Animal GetRandomAnimal()
        {
            // Renvoie un numéro aléatoire qui se trouve entre 0 et 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;
        }
    }
}
Exécution de l'exemple :

4- Le polymorphisme dans CSharp

Le polymorphisme  (Polymorphism) signifie avoir plusieurs formes. Dans le paradigme de programmation orienté objet, le polymorphisme est souvent exprimé comme «une interface, plusieurs fonctions».

Le polymorphisme peut être statique ou dynamique. En polymorphisme statique, la réponse à une fonction est déterminée à la compilation. En polymorphisme dynamique, il est décidé au moment de l'exécution (run-time).
Vous avez un chat chat asiatique (AsianCat), vous pouvez l'appeler un chat (Cat) ou l'appeler c'est un animal (Animal) qui est un aspect du polymorphisme.

Ou un autre exemple: sur votre CV, vous êtes un homme asiatique, alors que vous êtes un Vietnamien.

L'exemple ci-dessous vous montre comment se comporter entre la déclaration et la réalité
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)
        {
            // Vous déclarez un objet Animal (Animal).
            // En le créant par Constructeur de la classe Cat.
            // ** L'objet 'tom' déclaré est Animal
            // donc il ne peut qu'appeler les méthodes de Animal.
            Animal tom = new Cat("Tom", 3, 20); 

            // Appelez la méthode Sleep.
            tom.Sleep();

            // - Move() est la méthode définie dans la classe Animal.
            // - Move() est remplacée (override) dans la classe Cat.
            // 'tom' en effet est Cat, malgré qu'il est déclaré étant comme Animial.
            // ==> Il appelera la méthode Move() définie dans la classe Cat.
            tom.Move(); // ==> Cat Move.


            Console.ReadLine();
        }
    }
}
Vous avez 2 facons de reécrire une méthode définie dans la super-classe, en utilisant le mot-clé  override ou  new. Et ils sont très différent. Voyez l'illustration ci-dessus :
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)
        {
            // Vous déclarez un objet Animal.
            // Mais créez- le en utilisant le Constructeur de la classe Duck.
            Animal donald = new Duck("Donald");

            // Appelez la méthode Sleep() (Définie dans la classe Animal).
            donald.Sleep();

            // - Move() est la méthode définie dans la classe Animal.
            // - Move() est "réécrit" avec le mot-clé 'new' dans la classe Duck.
            //   ('new' Move() n'est qu'utilisée aux objets déclarés étant comme Duck ou sous-classe de Duck).
            // 'donald' est déclaré comme 'Animal', non 'Duck'.
            donald.Move(); // ==> Animal Move.


            Console.ReadLine();
        }
    }
}
Exécution de l'exemple :

View more Tutorials: