CodeGym /Cours /C# SELF /Surcharge des constructeurs

Surcharge des constructeurs

C# SELF
Niveau 16 , Leçon 4
Disponible

1. Introduction

Imaginons qu’on a une classe Person :

public class Person
{
    public string Name;
    public int Age;
    
    public Person(string name, int age)
    {
        Name = name;
        Age = age;
    }
}

Et là tu te sens presque comme un génie — tu peux créer des personnes avec n’importe quel nom et âge. Mais voilà le souci : parfois, il manque des infos ! L’utilisateur de ton appli a juste entré un nom, et l’âge sera connu plus tard. Ou alors tu veux parfois donner un âge "par défaut". Bien sûr, tu pourrais bidouiller, mais C# te propose une solution élégante pour ça — surcharge des constructeurs.

Surcharge des constructeurs veut dire qu’une classe peut avoir plusieurs constructeurs avec le même nom (le nom de la classe), mais avec des listes de paramètres différentes.

C’est quoi la différence entre ces listes ? Elles peuvent varier par :

  1. Le nombre de paramètres : Par exemple, un constructeur prend 2 paramètres, un autre — 3.
  2. Le type des paramètres : L’un prend (string, int), l’autre — (string, decimal).
  3. L’ordre des paramètres : (string, int) et (int, string) — ce sont des signatures différentes.

La règle la plus importante : le compilateur distingue les constructeurs (et n’importe quelle méthode) par leur signature. La signature, c’est le nom du constructeur (ou de la méthode) et la liste de ses paramètres (nombre, types et ordre). Les modificateurs d’accès (public, private) et, pour les méthodes normales, le type de retour, ne font pas partie de la signature. Mais les constructeurs n’ont pas de type de retour, et leur nom est toujours celui de la classe.

2. Surcharge des constructeurs : syntaxe et exemple


public class Cat
{
    public string Name;
    public string Color;

    // Constructeur sans paramètres
    public Cat()
    {
        Name = "Chat sans nom";
        Color = "Gris";
    }

    // Constructeur avec un paramètre
    public Cat(string name)
    {
        Name = name;
        Color = "Gris";
    }

    // Constructeur avec deux paramètres
    public Cat(string name, string color)
    {
        Name = name;
        Color = color;
    }
}

Utilisation :

Cat barsik = new Cat(); // "Chat sans nom", "Gris"
Cat murzik = new Cat("Murzik"); // "Murzik", "Gris"
Cat ryzhik = new Cat("Ryzhik", "Roux"); // "Ryzhik", "Roux"

Quand tu crées un objet et que tu donnes des paramètres, C# "devine" le bon constructeur grâce à leur nombre et leur type.

C’est super pratique ! L’utilisateur de ta classe n’a pas à donner des paramètres qu’il ne connaît pas : s’il veut juste un chat — il prend le constructeur sans paramètres, s’il connaît le nom — il utilise l’autre, etc. S’il veut choisir la couleur — il prend la troisième option.

3. Comment fonctionne l’appel des constructeurs surchargés ?

C# choisit le bon constructeur automatiquement à la compilation, selon le type et le nombre d’arguments que tu passes. Difficile de se tromper — si tu te plantes, le compilateur va râler direct.

Essayons d’ajouter un constructeur avec un paramètre entier :

public Cat(int age)
{
    Name = "Chat sans nom";
    Color = "Gris";
    // Code supplémentaire pour l’âge
}

Maintenant, on peut aussi créer un "chaton par âge" :

Cat oldCat = new Cat(5); // Ce sera le constructeur Cat(int age) qui sera appelé
Appel du constructeur Lequel sera appelé ?
new Cat()
Sans paramètres
new Cat("Murka")
Avec un paramètre string
new Cat("Ryzhik", "Roux")
Avec deux paramètres string
new Cat(10)
Avec un paramètre entier

4. Appels internes de constructeurs : le mot-clé this

Parfois, différents constructeurs font presque la même chose (ou carrément la même). Pour éviter de copier du code, tu peux "appeler un constructeur depuis un autre". Pour ça, on utilise le mot-clé this.


public class Cat
{
    public string Name;
    public string Color;

    public Cat() : this("Chat sans nom")
    {
        // Ce constructeur appelle Cat(string name)
    }

    public Cat(string name) : this(name, "Gris")
    {
        // Ce constructeur appelle Cat(string name, string color)
    }

    public Cat(string name, string color)
    {
        Name = name;
        Color = color;
    }
}

Au final :

  • new Cat() appelle Cat(string name), qui appelle Cat(string name, string color).
  • Toutes les "routes mènent à Rome" : toute l’initialisation est concentrée dans un seul "grand" constructeur.

Cette approche s’appelle constructor chaining (enchaînement des constructeurs).

5. Exemples de la vraie vie

Créons une classe héros (Hero) pour un jeu, avec un nom et un niveau ! Voilà comment on pourrait l’écrire :

Avec un seul constructeur :

public class Hero
{
    public string Name;
    public int Level;

    public Hero(string name, int level)
    {
        Name = name;
        Level = level;
    }
}

Et maintenant, permettons de le créer de plusieurs façons !

Plusieurs constructeurs :

public class Hero
{
    public string Name;
    public int Level;

    // Si rien n’est précisé, le héros sera "Sans nom" niveau 1
    public Hero() : this("Sans nom", 1)
    {
    }

    // Si on connaît juste le nom, niveau par défaut — 1
    public Hero(string name) : this(name, 1)
    {
    }

    // Le constructeur principal avec deux paramètres
    public Hero(string name, int level)
    {
        Name = name;
        Level = level;
    }
}

Maintenant, on peut créer un héros de plusieurs façons :

Hero h1 = new Hero();               // "Sans nom", 1
Hero h2 = new Hero("Arthur");        // "Arthur", 1
Hero h3 = new Hero("Laura", 10);     // "Laura", 10

6. Détails d’implémentation : pièges cachés et subtilités

Premièrement : le compilateur ne crée pas de constructeur "vide" par défaut si tu déclares au moins un autre constructeur. Donc, si tu as écrit ton propre constructeur avec paramètres mais oublié d’ajouter un constructeur sans paramètres, alors cet appel :

Hero h = new Hero(); // Erreur si le constructeur sans paramètres n’existe pas !
va donner une erreur de compilation.

Deuxièmement : si tu appelles le mauvais constructeur dans la chaîne, tu peux casser la logique d’initialisation. Il faut rester cohérent : le mieux, c’est que tout le vrai boulot soit fait dans le constructeur le plus complet, et que les autres ne fassent que passer les données via this(...).

Troisièmement : si les paramètres ne diffèrent que par leur type (genre Cat(string s) et Cat(object o)), tu peux te retrouver avec une confusion si tu appelles le constructeur avec un argument null. Le compilateur ne saura pas toujours lequel tu veux.

7. Surcharge et initialisation des champs

Souvent, une classe a des champs qu’il faut absolument définir. La surcharge des constructeurs rend ça pratique, mais c’est à toi de décider quelles valeurs par défaut sont logiques pour ta classe.

Exemple avec vérification :

public class Book
{
    public string Title;
    public int Year;

    // Livre par défaut — "Sans titre", année 2000
    public Book() : this("Sans titre", 2000)
    {
    }
    
    public Book(string title) : this(title, 2000)
    {
    }

    public Book(string title, int year)
    {
        Title = title;
        Year = year;
    }
}

8. Surcharge avec différents ensembles de paramètres

Il existe des classes où le nombre de constructeurs se compte par dizaines ! Ce n’est pas toujours un signe d’une bonne architecture (parfois il vaut mieux utiliser des méthodes de configuration ou le pattern "builder"), mais pour des objets utilisateurs, des modèles, des DTO — ça marche bien.

Exemple : une classe "Animal de compagnie", où tu peux préciser toutes les caractéristiques, ou juste les plus importantes.

public class Pet
{
    public string Name;
    public int Age;
    public string Type;
    public bool IsVaccinated;

    // Constructeur par défaut
    public Pet() : this("NoName", 0, "Cat", false) { }

    // Minimum d’infos
    public Pet(string name, string type) : this(name, 0, type, false) { }

    // Constructeur complet
    public Pet(string name, int age, string type, bool isVaccinated)
    {
        Name = name;
        Age = age;
        Type = type;
        IsVaccinated = isVaccinated;
    }
}
Différence entre la surcharge d’une méthode et d’un constructeur
Méthode normale Constructeur (y compris surchargé)
Peut être appelée à tout moment Appelée seulement à la création de l’objet (new)
Peut retourner une valeur de n’importe quel type Ne retourne jamais de valeur (pas de type indiqué)
Le nom de la méthode est libre, souvent un verbe Le nom est toujours celui de la classe
Peut être surchargée par les paramètres Peut aussi être surchargée par les paramètres
1
Étude/Quiz
Notion de classe et d'objet, niveau 16, leçon 4
Indisponible
Notion de classe et d'objet
Classes et constructeurs
Commentaires
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION