Partager via


abstract (référence C#)

Le abstract modificateur indique que sa cible a une implémentation manquante ou incomplète. Utilisez le modificateur abstrait avec des classes, des méthodes, des propriétés, des indexeurs et des événements. Dans une déclaration de classe, utilisez le modificateur abstract pour indiquer qu’une classe doit uniquement servir de classe de base pour d’autres classes, et ne pas être instanciée toute seule. Les classes non abstraites qui dérivent de la classe abstraite doivent implémenter des membres marqués comme abstraits.

La documentation de référence du langage C# décrit la version la plus récente du langage C#. Il contient également la documentation initiale des fonctionnalités dans les préversions publiques pour la prochaine version du langage.

La documentation identifie toute fonctionnalité introduite en premier dans les trois dernières versions de la langue ou dans les préversions publiques actuelles.

Conseil / Astuce

Pour savoir quand une fonctionnalité a été introduite en C#, consultez l’article sur l’historique des versions du langage C#.

Les classes abstraites peuvent contenir à la fois des membres abstraits (qui n’ont pas d’implémentation et doivent être substitués dans des classes dérivées) et des membres entièrement implémentés (tels que des méthodes, des propriétés et des constructeurs standard). Cette fonctionnalité permet aux classes abstraites de fournir des fonctionnalités courantes tout en exigeant des classes dérivées pour implémenter des membres abstraits spécifiques.

Note

Les membres de l’interface sont abstract par défaut.

Classe abstraite avec des membres mixtes

L’exemple suivant illustre une classe abstraite qui contient à la fois des méthodes implémentées et des membres abstraits :

namespace LanguageKeywords;

public abstract class Vehicle
{
    protected string _brand;
    
    // Constructor - implemented method in abstract class
    public Vehicle(string brand) => _brand = brand;
    
    // Implemented method - provides functionality that all vehicles share
    public string GetInfo() => $"This is a {_brand} vehicle.";
    
    // Another implemented method
    public virtual void StartEngine() => Console.WriteLine($"{_brand} engine is starting...");
    
    // Abstract method - must be implemented by derived classes
    public abstract void Move();
    
    // Abstract property - must be implemented by derived classes  
    public abstract int MaxSpeed { get; }
}

public class Car : Vehicle
{
    public Car(string brand) : base(brand) { }
    
    // Implementation of abstract method
    public override void Move() => Console.WriteLine($"{_brand} car is driving on the road.");
    
    // Implementation of abstract property
    public override int MaxSpeed => 200;
}

public class Boat : Vehicle
{
    public Boat(string brand) : base(brand) { }
    
    // Implementation of abstract method
    public override void Move() => Console.WriteLine($"{_brand} boat is sailing on the water.");
    
    // Implementation of abstract property
    public override int MaxSpeed => 50;
}

public class AbstractExample
{
    public static void Examples()
    {
        // Cannot instantiate abstract class: Vehicle v = new Vehicle("Generic"); // Error!
        
        Car car = new Car("Toyota");
        Boat boat = new Boat("Yamaha");
        
        // Using implemented methods from abstract class
        Console.WriteLine(car.GetInfo());
        car.StartEngine();
        
        // Using abstract methods implemented in derived class
        car.Move();
        Console.WriteLine($"Max speed: {car.MaxSpeed} km/h");
        
        Console.WriteLine();
        
        Console.WriteLine(boat.GetInfo());
        boat.StartEngine();
        boat.Move();
        Console.WriteLine($"Max speed: {boat.MaxSpeed} km/h");
    }
}

class Program
{
    static void Main()
    {
        AbstractExample.Examples();
    }
}
/* Output:
This is a Toyota vehicle.
Toyota engine is starting...
Toyota car is driving on the road.
Max speed: 200 km/h

This is a Yamaha vehicle.
Yamaha engine is starting...
Yamaha boat is sailing on the water.
Max speed: 50 km/h
*/

Dans cet exemple, la Vehicle classe abstraite fournit les éléments suivants :

  • Membres implémentés : GetInfo() méthode, StartEngine() méthode et constructeur : ces membres fournissent des fonctionnalités courantes pour tous les véhicules.
  • Membres abstraits : Move() méthode et MaxSpeed propriété : ces membres doivent être implémentés par chaque type de véhicule spécifique.

Cette conception permet à la classe abstraite de fournir des fonctionnalités partagées tout en garantissant que les classes dérivées implémentent un comportement spécifique au véhicule.

Classe concrète dérivée d’une classe abstraite

Dans cet exemple, la classe Square doit fournir une implémentation de GetArea, car elle dérive de la classe Shape :

abstract class Shape
{
    public abstract int GetArea();
}

class Square : Shape
{
    private int _side;

    public Square(int n) => _side = n;

    // GetArea method is required to avoid a compile-time error.
    public override int GetArea() => _side * _side;

    static void Main()
    {
        var sq = new Square(12);
        Console.WriteLine($"Area of the square = {sq.GetArea()}");
    }
}
// Output: Area of the square = 144

Les classes abstraites présentent les caractéristiques suivantes :

  • Vous ne pouvez pas créer une instance d’une classe abstraite.
  • Une classe abstraite peut contenir des méthodes et des accesseurs abstraits.
  • Une classe abstraite peut également contenir des méthodes, des propriétés, des champs et d’autres membres implémentés qui fournissent des fonctionnalités aux classes dérivées.
  • Vous ne pouvez pas utiliser le sealed modificateur sur une classe abstraite, car les deux modificateurs ont des significations opposées. Le modificateur sealed empêche qu’une classe soit héritée et le modificateur abstract exige qu’une classe soit héritée.
  • Une classe non abstraite dérivée d’une classe abstraite doit inclure des implémentations réelles de tous les accesseurs et méthodes abstraits hérités.

Utilisez le abstract modificateur dans une méthode ou une déclaration de propriété pour indiquer que la méthode ou la propriété ne contient pas d’implémentation.

Les méthodes abstraites présentent les caractéristiques suivantes :

  • Une méthode abstraite est implicitement une méthode virtuelle.

  • Les déclarations de méthodes abstraites sont autorisées uniquement dans les classes abstraites.

  • Étant donné qu’une déclaration de méthode abstraite ne fournit aucune implémentation réelle, il n’y a pas de corps de méthode. La déclaration de méthode se termine simplement par un point-virgule. Par exemple :

    public abstract void MyMethod();
    

    L’implémentation est fournie par une méthode override, qui est membre d’une classe non abstraite.

  • Il s’agit d’une erreur d’utilisation des static modificateurs ou virtual des modificateurs dans une déclaration de méthode abstraite dans un class type. Vous pouvez déclarer et static virtual méthodes static abstract dans les interfaces.

    Les propriétés abstraites se comportent comme les méthodes abstraites, à l’exception des différences dans la syntaxe de déclaration et d’appel.

  • Il s’agit d’une erreur d’utilisation du abstract modificateur sur une propriété statique dans un class type. Vous pouvez déclarer ou static virtual propriétés static abstract dans les déclarations d’interface.

  • Une propriété héritée abstraite peut être substituée dans une classe dérivée en incluant une déclaration de propriété qui utilise le override modificateur.

Pour plus d'informations sur les classes abstraites, consultez Classes abstract et sealed et membres de classe.

Une classe abstraite doit fournir une implémentation pour tous les membres d’interface. Une classe abstraite qui implémente une interface peut mapper les méthodes d’interface à des méthodes abstraites. Par exemple :

interface I
{
    void M();
}

abstract class C : I
{
    public abstract void M();
}

Dans l’exemple suivant, la classe DerivedClass dérive d’une classe BaseClassabstraite. La classe abstraite contient une méthode abstraite, AbstractMethod, et deux propriétés abstraites, X et Y.

// Abstract class
abstract class BaseClass
{
    protected int _x = 100;
    protected int _y = 150;

    // Abstract method
    public abstract void AbstractMethod();

    // Abstract properties
    public abstract int X { get; }
    public abstract int Y { get; }
}

class DerivedClass : BaseClass
{
    public override void AbstractMethod()
    {
        _x++;
        _y++;
    }

    public override int X   // overriding property
    {
        get
        {
            return _x + 10;
        }
    }

    public override int Y   // overriding property
    {
        get
        {
            return _y + 10;
        }
    }

    static void Main()
    {
        var o = new DerivedClass();
        o.AbstractMethod();
        Console.WriteLine($"x = {o.X}, y = {o.Y}");
    }
}
// Output: x = 111, y = 161

Dans l’exemple précédent, si vous tentez d’instancier la classe abstraite en utilisant une instruction comme celle-ci :

BaseClass bc = new BaseClass();   // Error

Vous obtenez une erreur indiquant que le compilateur ne peut pas créer d’instance de la classe abstraite « BaseClass ». Néanmoins, vous pouvez utiliser un constructeur de classe abstrait, comme illustré dans l’exemple suivant.

public abstract class Shape
{
    public string Color { get; set; }

    // Constructor of the abstract class
    protected Shape(string color)
    {
        Color = color;
        Console.WriteLine($"Created a shape with color {color}.");
    }

    // Abstract method that must be implemented by derived classes
    public abstract double CalculateArea();
}

public class Square : Shape
{
    public double Side { get; set; }

    // Constructor of the derived class calling the base class constructor
    public Square(string color, double side) : base(color)
    {
        Side = side;
    }

    public override double CalculateArea()
    {
        return Side * Side;
    }
}

public class Program
{
    public static void Main(string[] args)
     {
            Square square = new Square("red", 5);
            Console.WriteLine($"Area of the square: {square.CalculateArea()}");            
     }
}

La Shape classe est déclarée abstract, ce qui signifie que vous ne pouvez pas l’instancier directement. Au lieu de cela, il sert de blueprint pour d’autres classes.

  • Même si vous ne pouvez pas créer d’objets d’une classe abstraite, il peut toujours avoir un constructeur. Ce constructeur est généralement protected, ce qui signifie que seules les classes dérivées peuvent y accéder. Dans ce cas, le constructeur Shape prend un paramètre color et initialise la propriété Color. Il imprime également un message dans la console. La partie public Square(string color, double side) : base(color) appelle le constructeur de la classe de base (Shape) et lui transmet l’argument color.
  • Dans la Shape classe, le constructeur défini prend une couleur en tant que paramètre protected Shape(string color). Cela signifie que C# ne fournit plus automatiquement un constructeur sans paramètre par défaut. Les classes dérivées doivent utiliser l’expression : base(color) pour appeler le constructeur de base. La définition de la valeur par défaut sur la couleur protected Shape(string color="green") permet d’omettre l’expression : base(color) dans les classes dérivées. Le constructeur protected Shape(string color="green") définit la couleur en vert.

Spécification du langage C#

Pour plus d'informations, voir la spécification du langage C#. La spécification du langage est la source de référence pour la syntaxe C# et son utilisation.

Voir aussi