CodeGym /Cours /C# SELF /Méthodes et propriétés abstraites

Méthodes et propriétés abstraites

C# SELF
Niveau 22 , Leçon 2
Disponible

1. Méthodes abstraites

Dans la conf précédente, on a posé les bases : on a découvert les classes abstraites et vu qu’elles peuvent contenir des méthodes et propriétés abstraites. On a pigé que c’est un "contrat" qui oblige les classes dérivées à fournir leur propre implémentation.

Maintenant, on va creuser un peu plus et mater des scénarios plus complexes et utiles. Ici, on va se concentrer sur les subtilités de la syntaxe, sur comment l’abstraction marche dans des hiérarchies à plusieurs niveaux, et bien distinguer quand utiliser abstract et quand — virtual.

Une méthode abstraite, c’est un peu comme une vieille recette de cuisine mystérieuse : "ajoute un ingrédient secret" — lequel, on sait pas, mais tous les cuistots suivants doivent inventer un truc !

Une méthode abstraite est toujours dans une classe abstraite

Essayer de déclarer une méthode abstraite dans une classe normale (non-abstraite) va te donner une erreur de compil. Pourquoi ? Parce qu’une classe normale, tu peux l’instancier direct, et si tu tentes d’appeler une méthode pas définie ? Juste un regard chelou de ton IDE.


// Ça va faire une erreur de compilation :
public class WrongClass
{
    public abstract void Oops(); // Ça marche pas !
}

Si une classe a au moins une méthode abstraite, elle doit obligatoirement être marquée abstract !

Implémentation des méthodes abstraites dans les classes dérivées

On implémente avec le mot-clé override. Une classe qui hérite d’une classe abstraite et qui n’implémente pas toutes les méthodes abstraites doit elle-même être abstraite (sinon le compilateur va râler).

On continue avec notre appli :

Dans les confs précédentes, on a créé une classe Shape (figure), où on a déclaré une méthode abstraite pour calculer l’aire. Maintenant, on va créer des figures concrètes :


public class Rectangle : Shape
{
    public double Width { get; }
    public double Height { get; }

    public Rectangle(double width, double height)
    {
        Width = width;
        Height = height;
    }

    public override double CalculateArea()
    {
        return Width * Height;
    }
}

public class Circle : Shape
{
    public double Radius { get; }

    public Circle(double radius)
    {
        Radius = radius;
    }

    public override double CalculateArea()
    {
        return Math.PI * Radius * Radius;
    }
}

Pourquoi les méthodes abstraites sont si importantes ?

Les méthodes abstraites, c’est ta façon de dire : "Les gars, si vous héritez de cette classe, décidez comment ça doit marcher !" Ça rend l’architecture du programme plus claire, ça évite les oublis, et surtout, ça permet d’utiliser le polymorphisme à fond.

2. Propriétés abstraites (properties)

C’est quoi une propriété abstraite

Une propriété abstraite, c’est le même contrat qu’une méthode abstraite, mais pour une propriété (property). En C#, c’est super naturel, parce que les propriétés sont un des moyens principaux d’encapsuler des données. Une propriété abstraite dit : "Laisse les enfants décider eux-mêmes où choper (et peut-être comment setter) la valeur de cette propriété".

Exemple :
On ajoute la propriété Name à la figure — chaque enfant doit l’avoir, mais chacun décide quoi renvoyer.


public abstract class Shape
{
    public abstract string Name { get; }

    public abstract double CalculateArea();
}

Maintenant, chaque enfant doit implémenter cette propriété :


public class Rectangle : Shape
{
    public double Width { get; }
    public double Height { get; }
    public override string Name => "Rectangle";

    public Rectangle(double width, double height)
    {
        Width = width;
        Height = height;
    }

    public override double CalculateArea()
    {
        return Width * Height;
    }
}

public class Circle : Shape
{
    public double Radius { get; }
    public override string Name => "Cercle";

    public Circle(double radius)
    {
        Radius = radius;
    }

    public override double CalculateArea()
    {
        return Math.PI * Radius * Radius;
    }
}

Particularités de la syntaxe

Une propriété abstraite, c’est comme dans une interface : tu la déclares sans corps, mais tu précises si elle aura juste un getter, ou aussi un setter.


public abstract class Creature
{
    // propriété en lecture seule
    public abstract string Species { get; }

    // propriété en lecture/écriture
    public abstract int Age { get; set; }
}

Dans la classe qui implémente, tu peux définir la logique pour obtenir (et si besoin — modifier) la valeur.

Pourquoi utiliser des propriétés abstraites

Une propriété abstraite, c’est top quand tu veux que chaque enfant décide comment obtenir ou stocker la valeur. C’est super utile en modélisation, dans les modèles métiers, les view-models, et partout où la logique de la propriété est plus complexe qu’un simple champ.

Par exemple, si une figure a un nom calculé par une formule, et une autre renvoie juste une constante, tu peux tout planquer joliment derrière une propriété abstraite.

3. Schéma : comment sont liés classe abstraite, méthodes et propriétés

Regarde ce schéma pour voir comment ça marche :


┌─────────────┐
│ abstract    │
│   Shape     │
│-------------│
│ +Name: str  │  <-- propriété abstraite
│ +Area(): dbl│  <-- méthode abstraite
└─────┬───────┘
      │
 ┌────▼────┐      ┌───────┐
 │Rectangle│      │ Cercle│
 │........ │ .... │ ......│
 │+Name    │      │+Name  │
 │+Area()  │      │+Area()│
 └─────────┘      └───────┘

Comme ça, on a UNE interface pour bosser avec n’importe quel enfant de la classe Shape, mais chaque enfant fait ce qu’il veut "sous le capot".

Diagramme UML pour méthode et propriété abstraites :


┌────────────────────────────┐
│        abstract class      │
│           Animal           │
│────────────────────────────│
│+ Name: string {abstract}   │
│+ MakeSound(): void {abstract}│
└─────────────┬──────────────┘
              │
     ┌────────┴──────────┐
     │                   │
┌────────────┐     ┌─────────────┐
│    Chat    │     │    Chien    │
│────────────│     │─────────────│
│+ Name      │     │+ Name       │
│+ MakeSound()│    │+ MakeSound()│
└────────────┘     └─────────────┘

4. Scénarios pratiques et utilité pour des vrais projets

Les méthodes et propriétés abstraites, c’est ton outil si tu conçois des hiérarchies de classes qui doivent évoluer. C’est la base pour des grosses applis métier, des modèles de domaines complexes, des systèmes de plugins, des frameworks UI, où tu poses la "loi" de base obligatoire pour tous les enfants.

Dans les vrais projets, ce genre de solutions "propres" permettent, même après des mois ou des années, d’ajouter de nouvelles entités et fonctions sans crainte, parce que l’ancien code gère déjà tous les cas de figure.

La question "pourquoi" et retour au polymorphisme

Le polymorphisme, ça a l’air magique, mais en vrai c’est juste un contrat : "tu peux appeler une méthode sur n’importe quel objet de la famille, et toujours avoir le bon résultat". Les méthodes et propriétés abstraites, c’est la façon de forcer toute la hiérarchie à parler le même langage, mais sans imposer une implémentation "par défaut".

Ce principe est super utilisé dans les systèmes de plugins (IDE, éditeurs graphiques, CRM), quand des devs tiers créent leurs extensions mais doivent implémenter un minimum de fonctions exigées par la plateforme. Par exemple, si tu codes un module pour gérer des fichiers, la classe de base peut avoir une propriété abstraite FileExtension et une méthode abstraite Open(), pour que chaque plugin gère bien ses propres fichiers.

Différences entre membres abstraits, virtuels et classiques

Caractéristique Méthode/propriété classique virtual abstract
Implémentation présente Oui Oui Non
Override obligatoire Non Non (on peut override) Oui (obligatoire dans l’enfant)
Appel direct possible Oui Oui Non
Peut être dans une classe normale Oui Oui Non
Peut être marqué sealed Non Oui Non

5. Utilisation dans notre appli d’apprentissage

Maintenant qu’on a tout ça, revenons à notre appli avec les figures et voyons comment propriétés et méthodes abstraites bossent ensemble pour créer un système flexible et clair.


// Par exemple, dans la méthode principale du programme
List<Shape> shapes = new List<Shape>
{
    new Rectangle(4, 5),
    new Circle(2.5)
};

foreach (Shape shape in shapes)
{
    // Grâce à la propriété abstraite Name et à la méthode CalculateArea,
    // on se fiche du type concret de la figure
    Console.WriteLine($"{shape.Name}, Aire : {shape.CalculateArea():F2}");
}

Résultat :

Rectangle, Aire : 20.00
Cercle, Aire : 19.63

C’est beau : le code ne sait pas et s’en fiche de quel type est la figure — il appelle juste les bonnes propriétés et méthodes, et le CLR de .NET gère la bonne implémentation !

6. Erreurs fréquentes et particularités d’implémentation

Erreur n°1 : méthode abstraite du parent non implémentée.
Si dans une classe dérivée il reste au moins une méthode ou propriété abstraite non implémentée, et que la classe n’est pas marquée abstract, le compilateur refusera de builder le projet. C’est une bonne protection : tu ne peux pas créer un objet avec une logique "trouée" — genre une figure sans méthode CalculateArea().

Erreur n°2 : méthode déclarée abstract, mais classe non abstraite.
Ce code ne compile pas non plus. Si tu ajoutes une méthode abstract dans une classe, la classe doit être abstraite :


public abstract class Polygon : Shape
{
    // On n’implémente pas CalculateArea(), la classe reste abstract
}

Erreur n°3 : tentative d’implémenter une méthode abstraite avec virtual.
Une méthode abstraite doit être implémentée avec le mot-clé override, pas virtual. Mais si tu veux que l’implémentation puisse être overridée plus loin dans la hiérarchie, tu peux d’abord override la méthode, puis la déclarer virtual dans la classe fille :


public override double CalculateArea()
{
    // Implémentation par défaut...
}

Dans un enfant plus profond, tu peux override à nouveau. Mais tu ne peux plus la remettre abstract, vu qu’il y a déjà une implémentation.

Commentaires
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION