Héritage (Guide de programmation C#)

Mise à jour : Juillet 2008

L'héritage, avec l'encapsulation et le polymorphisme, est l'une des trois caractéristiques principales (ou « piliers ») de la programmation orientée objet. Il vous permet de créer de nouvelles classes qui réutilisent, étendent et modifient le comportement défini dans d'autres classes. La classe dont les membres sont hérités porte le nom de classe de base et la classe qui hérite de ces membres porte le nom de classe dérivée.

Remarque :

Les structs ne prennent pas en charge l'héritage, mais ils peuvent implémenter des interfaces. Pour plus d'informations, consultez Interfaces (Guide de programmation C#).

Conceptuellement, une classe dérivée est une spécialisation de la classe de base. Par exemple, si vous avez une classe de base Animal, vous pouvez avoir une classe dérivée nommée Mammal et une autre classe dérivée nommée Reptile. Un Mammal est un Animal et un Reptile est un Animal, mais chaque classe dérivée représente des spécialisations différentes de la classe de base.

Lorsque vous définissez une classe à dériver d'une autre classe, la classe dérivée obtient implicitement tous les membres de la classe de base, à l'exception de ses constructeurs et destructeurs. La classe dérivée peut ainsi réutiliser le code dans la classe de base sans avoir à le réimplémenter. Dans la classe dérivée, vous pouvez ajouter davantage de membres. De cette manière, la classe dérivée étend la fonctionnalité de la classe de base.

L'illustration suivante montre une classe WorkItem qui représente un élément de travail dans un processus métier. Comme toutes les classes, il dérive de System.Object et hérite de toutes ses méthodes. WorkItem ajoute cinq de ses membres. Cela inclut un constructeur, car les constructeurs ne sont pas hérités. ChangeRequest hérite de WorkItem et représente un type particulier d'élément de travail. ChangeRequest ajoute deux membres supplémentaires aux membres qu'il hérite de WorkItem et Object. Il doit ajouter son propre constructeur et il ajoute également un membre qui permettra au ChangeRequest d'être associé au WorkItem d'origine auquel la modification s'applique.

Héritage de classe

L'exemple suivant illustre la manière dont les relations de classe démontrées dans l'illustration précédente sont exprimées en C#. Il indique également comment WorkItem substitue la méthode virtuelle Object.ToString et comment la classe ChangeRequest hérite de l'implémentation WorkItem de la méthode.

// WorkItem implicitly inherits from Object class
public class WorkItem
{
    private static int nextID;
    protected int ID { get; set; }
    protected TimeSpan jobLength { get; set; }
    protected string Title { get; set; }
    protected string Description { get; set; }
    // Default constructor
    public WorkItem() 
    {
        ID = 0;
        Title = "Default title";
        Description = "Default description.";
        jobLength = new TimeSpan();
    }
    // Static constructor for static member.
    static WorkItem()
    {
        nextID = 0;
    }
    // Instance constructor.
    public WorkItem( string title, string desc, TimeSpan joblen)
    {
        this.ID = GetNextID();                
        this.Title = title;
        this.Description = desc;
        this.jobLength = joblen;
    }
    protected int GetNextID()
    {
       return ++nextID;
    }
    public void Update(string title, TimeSpan joblen)
    {
        this.Title = title;
        this.jobLength = joblen;
    }

    // Virtual method override.
    public override string ToString()
    {
        return String.Format("{0} - {1}", this.ID, this.Title); 
    }
}

// ChangeRequest derives from WorkItem and adds two of its own members.
public class ChangeRequest : WorkItem
{
    protected int originalItemID {get; set;}
    public ChangeRequest() { }
    public ChangeRequest(string title, string desc, TimeSpan jobLen, int originalID)
    {
        this.ID = GetNextID();
        this.Title = title;
        this.Description = desc;
        this.jobLength = jobLen;
        this.originalItemID = originalID;
    }
}

class Program
{
    static void Main()
    {
        WorkItem item = new WorkItem(                                
                        "Fix Bugs", 
                        "Fix all bugs in my source code branch",
                        new TimeSpan(3, 4, 0, 0));

        ChangeRequest change = new ChangeRequest("Change design of base class",
                                                 "Add members to base class",
                                                 new TimeSpan(4, 0, 0),
                                                 1);

        Console.WriteLine(item.ToString());

        // ChangeRequest inherits WorkItem's override of ToString
        Console.WriteLine(change.ToString()); 

        // Keep the console open in debug mode.
        Console.WriteLine("Press any key to exit.");
        Console.ReadKey();
    }
}
/* Output:
    1 - Fix Bugs
    2 - Change design of base class
*/

Méthodes virtuelles et abstraites

Lorsqu'une classe de base déclare une méthode comme virtuelle, une classe dérivée peut substituer la méthode avec sa propre implémentation. Si une classe de base déclare un membre comme abstrait, cette méthode doit être substituée dans toute classe non abstraite qui hérite directement de cette classe. Si une classe dérivée est elle-même abstraite, elle hérite des membres abstraits sans les implémenter. Les membres virtuels et abstraits sont la base du polymorphisme, qui est la deuxième caractéristique principale de la programmation orientée objet. Pour plus d'informations, consultez Polymorphisme (Guide de programmation C#).

Classes de base abstraites

Vous pouvez déclarer une classe comme abstraite si vous souhaitez empêcher l'instanciation directe au moyen du mot clé new . Dans ce cas, la classe peut être utilisée uniquement si une classe nouvelle est dérivée d'elle. Une classe abstraite peut contenir une ou plusieurs signatures de méthode qui elles-mêmes sont déclarées comme abstraites. Ces signatures spécifient les paramètres et valeurs de retour, mais n'ont aucune implémentation (corps de méthode). Il n'est pas obligatoire qu'une classe abstraite contienne des membres abstraits ; toutefois, si une classe contient un membre abstrait, la classe elle-même doit être déclarée comme abstraite. Les classes dérivées qui ne sont pas elles-mêmes abstraites doivent fournir l'implémentation pour toute méthode abstraite à partir d'une classe de base abstraite. Pour plus d'informations, consultez Classes abstract et sealed et membres de classe (Guide de programmation C#) et Conception de classes abstraites.

Interfaces

Une interface est un type référence quelque peu semblable à une classe de base abstraite qui se compose uniquement de membres abstraits. Lorsqu'une classe dérive d'une interface, elle doit fournir une implémentation pour tous les membres de l'interface. Une classe peut implémenter plusieurs interfaces, bien qu'elle puisse dériver d'une classe de base directe unique.

Les interfaces sont utilisées pour définir des fonctions spécifiques pour les classes qui n'ont pas nécessairement de relation « est un ». Par exemple, l'interface IEquatable[`1] peut être implémentée par toute classe ou struct qui doit activer le code client pour déterminer si deux objets du type sont équivalents (quelle que soit la manière dont le type définit l'équivalence). IEquatable<T> n'implique pas le même type de relation « est un » qui existe entre une classe de base et une classe dérivée (par exemple, un Mammal est un Animal). Pour plus d'informations, consultez Interfaces (Guide de programmation C#).

Accès de classe dérivée aux membres de la classe de base

Une classe dérivée a accès aux membres publics, protégés, internes et internes protégés d'une classe de base. Bien qu'une classe dérivée hérite des membres privés d'une classe de base, elle ne peut pas accéder à ces membres. Toutefois, tous ces membres privés sont quand même présents dans la classe dérivée et peuvent effectuer le même travail que dans la classe de base elle-même. Par exemple, supposez qu'une méthode de classe de base protégée accède à un champ privé. Ce champ doit être présent dans la classe dérivée pour que la méthode de classe de base héritée fonctionne correctement.

Empêcher la dérivation supplémentaire

Une classe peut empêcher d'autres classes d'hériter d'elle, ou de l'un de ses membres, en se déclarant elle-même ou le membre comme sealed. Pour plus d'informations, consultez Classes abstract et sealed et membres de classe (Guide de programmation C#).

Masquage des membres de la classe de base par la classe héritée

Une classe dérivée peut masquer des membres de la classe de base en déclarant ces membres avec les mêmes nom et signature. Le modificateur new peut être utilisé pour indiquer explicitement que le membre n'est pas censé être une substitution du membre de base. L'utilisation de new n'est pas obligatoire, mais un avertissement du compilateur est généré si new n'est pas utilisé. Pour plus d'informations, consultez Versioning avec les mots clés override et new (Guide de programmation C#) et Savoir quand utiliser les mots clés override et new (Guide de programmation C#).

Voir aussi

Concepts

Guide de programmation C#

Référence

Classes et structs (Guide de programmation C#)

class (Référence C#)

struct (Référence C#)

Historique des modifications

Date

Historique

Raison

Juillet 2008

Ajout de contenu, d'une illustration et de nouveaux exemples.

Améliorations apportées aux informations.