Héritage
Vous avez étudié le concept de classes dérivées dans la section précédente. Cette fonctionnalité d'une classe à hériter des propriétés d'une autre classe s'appelle héritage.
Bien que vous connaissiez déjà le concept d'héritage, vous l'aborderez cette fois de manière un peu plus approfondie afin de mieux le comprendre.
Pour une révision rapide, voici un exemple d'héritage :
index.cs
1234567891011121314151617181920212223242526272829303132333435363738394041424344#pragma warning disable CS0169 // To disable some unnecessary compiler warnings for this example. Using this is not a recommended practice. using System; class Mammal { int age; float weight; // kilogram (1 kg = 2.2 pounds) } class Dog : Mammal { string breed; public void speak() { Console.WriteLine("Woof!"); } } class Cat : Mammal { string furPattern; public void speak() { Console.WriteLine("Meow!"); } } class ConsoleApp { static void Main() { Cat myCat = new Cat(); Dog myDog = new Dog(); myCat.speak(); myDog.speak(); } }
La directive #pragma warning disable "warning code"
peut être utilisée pour désactiver certains avertissements du compilateur. Il est généralement déconseillé de désactiver les avertissements, car les ignorer peut entraîner un comportement inattendu du programme.
Le code ci-dessus contient une classe parente appelée Mammal
et deux classes dérivées appelées Cat
et Dog
.
Notez qu'aucune des classes n'a de constructeur explicitement défini, ce qui signifie que ces classes utiliseront un constructeur par défaut lors de la création d'un objet.
Un constructeur par défaut est automatiquement fourni par le langage de programmation si une classe ne possède aucun constructeur explicitement défini. Un constructeur par défaut est essentiellement un constructeur vide qui ne contient aucun code, par exemple public className() {}
est ce à quoi pourrait ressembler un constructeur par défaut. Puisqu'il n'initialise explicitement aucun attribut, tous les attributs prennent des valeurs par défaut - également appelées valeurs nulles.
Créons manuellement un constructeur pour la classe Mammal
, qui initialise un objet Mammal
avec certaines données :
index.cs
12345678910111213141516171819202122232425262728293031323334353637383940414243444546#pragma warning disable CS0169 // To disable some unnecessary compiler warnings for this example. Using this is not a recommended practice. using System; class Mammal { int age; float weight; // kg public Mammal(int age, float weight) { this.age = age; this.weight = weight; } } class Dog : Mammal { string breed; public void speak() { Console.WriteLine("Woof!"); } } class Cat : Mammal { string furPattern; public void speak() { Console.WriteLine("Meow!"); } } class ConsoleApp { static void Main() { // Creating a "Mammal" object with some data Mammal m1 = new Mammal(10, 42.0f); } }
Si vous essayez de compiler ce programme, des erreurs apparaîtront dans la console. Pour comprendre ces erreurs, il est nécessaire de saisir deux concepts importants liés aux constructeurs.
Le premier est que, dès que vous définissez explicitement un constructeur pour une classe, cette classe ne possède plus de constructeur par défaut. Ainsi, le constructeur défini explicitement devient le constructeur principal de cette classe, qui dans ce cas est :
index.cs
12345public Mammal(int age, float weight) { this.age = age; this.weight = weight; }
Par conséquent, lors de la création d’un nouvel objet, il est toujours nécessaire de fournir les arguments requis du constructeur dans le bon ordre :
index.cs
1234567// Incorrect ways to create 'Mammal', will show an error Mammal m1 = new Mammal(); Mammal m1 = new Mammal(10); Mammal m1 = new Mammal(42.0f); // Correct way to create 'Mammal', will execute fine. Mammal m1 = new Mammal(10, 42.0f);
Deuxièmement, les classes dérivées peuvent également avoir des constructeurs ; cependant, avant que le constructeur d’une classe dérivée ne soit appelé, le constructeur de la classe de base (parente) est également appelé :
index.cs
1234567891011121314151617181920212223242526272829303132333435#pragma warning disable CS0169 // To disable some unnecessary warnings, using this is not a recommended practice. using System; class Mammal { int age; float weight; // kg // No attribute is initialized explicitly in this constructor // Hence, all attributes will take up "zero" values // It is similar to a "default" constructor except it outputs a message public Mammal() { Console.WriteLine("Mammal Constructor Called"); } } class Dog : Mammal { string breed; public Dog() { Console.WriteLine("Dog Constructor Called"); } } class ConsoleApp { static void Main() { Dog myDog = new Dog(); } }
Lorsque vous exécutez ce code, vous constatez que la méthode WriteLine()
du constructeur de 'Mammal', qui est la classe parente, est automatiquement appelée. Cela signifie qu'il s'agit d'une règle selon laquelle le constructeur de la classe de base (également appelé constructeur de base) est toujours appelé avant le constructeur de la classe dérivée.
Cette règle s'applique également dans le cas d'une héritage multiniveau :

Dans le schéma ci-dessus, le constructeur de Kitten
appelle le constructeur de Cat
avant le sien, cependant, puisque Cat
est également une classe dérivée, il appelle le constructeur de Mammal
avant le sien, et Mammal
appelle le constructeur de Animal
avant le sien. Ainsi, le premier constructeur exécuté est celui de la super classe — c'est-à-dire le constructeur de la classe Animal
, puis l'exécution descend dans la hiérarchie.
Si le constructeur de la classe parente ne prend aucun argument, il est automatiquement appelé par le compilateur, c'est la raison pour laquelle le constructeur de 'Mammal' dans l'exemple ci-dessus a été appelé automatiquement. Cependant, examinons à nouveau le code erroné :
index.cs
12345678910111213141516171819202122232425262728293031323334353637383940414243using System; class Mammal { int age; float weight; // kg public Mammal(int age, float weight) { this.age = age; this.weight = weight; } } class Dog : Mammal { string breed; public void speak() { Console.WriteLine("Woof!"); } } class Cat : Mammal { string furPattern; public void speak() { Console.WriteLine("Meow!"); } } class ConsoleApp { static void Main() { // Creating a "Mammal" object with some data Mammal m1 = new Mammal(10, 42.0f); } }
Dans le code ci-dessus, deux erreurs apparaissent, indiquant essentiellement que les constructeurs de base n'ont pas été appelés manuellement — puisqu'ils nécessitent des arguments, il faut les appeler explicitement. La syntaxe de base pour appeler manuellement le constructeur de la classe parente est la suivante :
index.cs
12345678910class DerivedClassName : ParentClassName { // ... attributes // ... methods public DerivedClassName(int arg1, int arg2, ...) : base(arg1, arg2, ...) { // code here } }
Exemple :
index.cs
1234567891011121314151617181920212223242526272829303132using System; class ExampleParentClass { int value1; int value2; public ExampleParentClass(int value1, int value2) { this.value1 = value1; } } class ExampleDerivedClass : ExampleParentClass { int value3; // The value1 and value2 arguments are passed to the base class's contructor public ExampleDerivedClass(int value1, int value2, int value3) : base (value1, value2) { this.value3 = value3; } } class ConsoleApp { static void Main() { var testObject = new ExampleDerivedClass(5, 7, 9); } }
En utilisant cette syntaxe, il est possible de transmettre toutes les données requises au constructeur Mammal
via les constructeurs Cat
et Dog
afin de corriger l’erreur rencontrée précédemment :
index.cs
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758using System; class Mammal { int age; float weight; // kg public Mammal(int age, float weight) { this.age = age; this.weight = weight; } } class Dog : Mammal { string breed; public Dog(int age, float weight, string breed) : base(age, weight) { this.breed = breed; } public void speak() { Console.WriteLine("Woof!"); } } class Cat : Mammal { string furPattern; public Cat(int age, float weight, string furPattern) : base(age, weight) { this.furPattern = furPattern; } public void speak() { Console.WriteLine("Meow!"); } } class ConsoleApp { static void Main() { // Creating a "Mammal" object with some data Mammal m1 = new Mammal(10, 42.0f); // Creating a "Dog" object with some data Dog d1 = new Dog(10, 42.5f, "Dobermann"); Console.WriteLine("Executed Successfully"); } }
Une autre caractéristique importante des constructeurs est la possibilité de les surcharger, tout comme pour toute autre méthode. Il est possible de créer plusieurs constructeurs avec un nombre d’arguments différent :
index.cs
12345678910111213141516171819202122232425class Mammal { int age; float weight; // kg // 1st constructor public Mammal() { // We leave it empty for this example // Since it's empty, it mimics the "default" constructor } // 2nd constructor public Mammal(int age) { this.age = age; } // 3rd constructor public Mammal(int age, float weight) { this.age = age; this.weight = weight; } }
Dans ce cas, la classe Mammal
possède 3 constructeurs. Il est donc possible d'initialiser ou de créer un objet mammifère de 3 manières différentes, et le compilateur choisira quel constructeur appeler en fonction du nombre et du type d'arguments :
index.cs
1234// All Correct var m1 = new Mammal(); var m2 = new Mammal(10); var m3 = new Mammal(10, 42.5f);
Cela signifie également que vous pouvez appeler n'importe lequel des 3 constructeurs depuis les constructeurs de la classe dérivée. Par exemple, toutes les options suivantes sont valides :
index.cs
123456789101112131415161718// Using 3rd base constructor public Dog(int age, float weight, string breed) : base(age, weight) { this.breed = breed; } // Using 2nd base constructor public Dog(int age, string breed) : base(age) { this.breed = breed; } // Using 1st base constructor // If the base constructor has no arguments then it is automatically called (similar to the default constructor), so we don't necessarily need to write 'base()' public Dog(string breed) { this.breed = breed; }
Assemblons les deux extraits ci-dessus et ajoutons quelques instructions Console.WriteLine
afin d'observer dans quel ordre les constructeurs sont exécutés, pour constater les résultats de manière pratique :
index.cs
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394using System; class Mammal { int age; float weight; // kg // 1st Constructor public Mammal() { // We leave it empty for this example // Since it's empty, it mimics the "default" constructor // The attributes are initialized with zero values Console.WriteLine("Mammal - Constructor 1 Called"); } // 2nd Constructor public Mammal(int age) { this.age = age; Console.WriteLine("Mammal - Constructor 2 Called"); } // 3rd Constructor public Mammal(int age, float weight) { this.age = age; this.weight = weight; Console.WriteLine("Mammal - Constructor 3 Called"); } } class Dog : Mammal { string breed; public Dog() { Console.WriteLine("Dog - Constructor 1 Called"); } // Using 1st Mammal constructor // We don't necessarily need to write 'base()' in this case // It automatically finds and calls the constructor with no arguments public Dog(string breed) { this.breed = breed; Console.WriteLine("Dog - Constructor 2 Called"); } // Using 2nd Mammal constructor public Dog(int age, string breed) : base(age) { this.breed = breed; Console.WriteLine("Dog - Constructor 3 Called"); } // Using 3rd Mammal constructor public Dog(int age, float weight, string breed) : base(age, weight) { this.breed = breed; Console.WriteLine("Dog - Constructor 4 Called"); } public void speak() { Console.WriteLine("Woof!"); } } class ConsoleApp { static void Main() { // Creating a "Mammal" object using different constructors Mammal m1 = new Mammal(10, 42.0f); Mammal m2 = new Mammal(10); Mammal m3 = new Mammal(); Console.WriteLine("----------"); // Seperator, for ease of reading output // Creating a "Dog" object using different constructors Dog d1 = new Dog(10, 42.0f, "Dobermann"); Console.WriteLine(""); Dog d2 = new Dog(10, "Dobermann"); Console.WriteLine(""); Dog d3 = new Dog("Dobermann"); Console.WriteLine(""); Dog d4 = new Dog(); } }
Maintenant que vous connaissez les différentes fonctionnalités de l'héritage, il est également important de savoir comment et quand les utiliser correctement. Voici quelques points à garder à l'esprit lors de la conception d'une structure de classe basée sur l'héritage :
Équilibre entre simplicité et flexibilité : La surcharge de constructeurs permet d'avoir plusieurs constructeurs acceptant différents types d'arguments, mais en abuser peut rendre le code plus complexe et difficile à maintenir. Il est recommandé de garder le code de la classe court, concis et pratique. Évitez de créer trop de constructeurs pour une classe afin de maintenir un équilibre entre simplicité et flexibilité.
Garder les constructeurs simples : Les constructeurs doivent principalement servir à initialiser un objet avec des données de base. Il est conseillé d'éviter tout traitement inutile et toute logique complexe à l'intérieur d'un constructeur. Si un calcul ou une logique est nécessaire, il est préférable de créer une méthode séparée pour cela.
;Mauvaise pratique:;
index.cs
123456789101112131415161718192021222324252627class Customer { string name; string accountType; double balance; public Customer (string name, string accountType, double balance) { this.name = name; this.accountType = accountType; if (accountType == "Savings") { // Plus 1 Percent this.balance = balance + balance * 0.01; } else if (accountType == "HighYieldSavings") { // Plus 5 percent this.balance = balance + balance * 0.05; } else { this.balance = balance; } } }
Bonne pratique :
index.cs
123456789101112131415161718192021222324252627282930class Customer { string name; string accountType; double balance; public Customer (string name, string accountType, double balance) { this.name = name; this.accountType = accountType; this.balance = balance; monthlyInterest(); } // This method might be used in other places too private void monthlyInterest() { if(accountType == "Savings") { // Plus 1 Percent balance += balance * 0.01; } else if(accountType == "HighYieldSavings") { // Plus 5 percent balance += balance * 0.05; } } }
Initialiser les attributs importants : il est nécessaire d'initialiser tous les attributs importants d'un objet avec des valeurs correctes afin de garantir leur bon fonctionnement, même s'il s'agit d'un constructeur sans arguments.
Mauvaise pratique :
index.cs
123456789101112131415public class Car { private string brand; private string model; private int year; private double price; // Constructor does not initialize important attributes // It is also generally not a good idea to have constructors without any arguments if they're not needed. public Car() { // No initialization of attributes Console.WriteLine("Car Created"); } }
Bonne pratique :
index.cs
123456789101112131415161718192021222324252627282930313233343536373839public class Car { private string brand; private string model; private int year; private double price; // Good: Constructor initializes important attributes // It also checks if the values are correct // In this case the if-else statements are not unnecessary since they are important for ensuring that the object functions correctly. public Car(string brand, string model, int year, double price) { this.brand = brand; this.model = model; // Validate and set the year // The first public car was created in 1886 :) if (year > 1886) { this.year = year; } else { Console.WriteLine("Invalid year. Setting year to default."); this.year = DateTime.Now.Year; // Set to current year as default } // Validate and set the price if (price >= 0) { this.price = price; } else { Console.WriteLine("Invalid price. Setting price to default."); this.price = 0; // Set to a default value } } }
1. Quelle fonctionnalité permet de créer plusieurs constructeurs pour une classe ?
2. Vous pourriez avoir besoin d'utiliser l'un des concepts des sections précédentes dans ce quiz. Le code ci-dessous comporte une erreur aux lignes 15 et 16. Examinez attentivement le code et décidez quelle est la correction la plus efficace pour cette erreur :
Merci pour vos commentaires !
Demandez à l'IA
Demandez à l'IA
Posez n'importe quelle question ou essayez l'une des questions suggérées pour commencer notre discussion
Awesome!
Completion rate improved to 2.04
Héritage
Glissez pour afficher le menu
Vous avez étudié le concept de classes dérivées dans la section précédente. Cette fonctionnalité d'une classe à hériter des propriétés d'une autre classe s'appelle héritage.
Bien que vous connaissiez déjà le concept d'héritage, vous l'aborderez cette fois de manière un peu plus approfondie afin de mieux le comprendre.
Pour une révision rapide, voici un exemple d'héritage :
index.cs
1234567891011121314151617181920212223242526272829303132333435363738394041424344#pragma warning disable CS0169 // To disable some unnecessary compiler warnings for this example. Using this is not a recommended practice. using System; class Mammal { int age; float weight; // kilogram (1 kg = 2.2 pounds) } class Dog : Mammal { string breed; public void speak() { Console.WriteLine("Woof!"); } } class Cat : Mammal { string furPattern; public void speak() { Console.WriteLine("Meow!"); } } class ConsoleApp { static void Main() { Cat myCat = new Cat(); Dog myDog = new Dog(); myCat.speak(); myDog.speak(); } }
La directive #pragma warning disable "warning code"
peut être utilisée pour désactiver certains avertissements du compilateur. Il est généralement déconseillé de désactiver les avertissements, car les ignorer peut entraîner un comportement inattendu du programme.
Le code ci-dessus contient une classe parente appelée Mammal
et deux classes dérivées appelées Cat
et Dog
.
Notez qu'aucune des classes n'a de constructeur explicitement défini, ce qui signifie que ces classes utiliseront un constructeur par défaut lors de la création d'un objet.
Un constructeur par défaut est automatiquement fourni par le langage de programmation si une classe ne possède aucun constructeur explicitement défini. Un constructeur par défaut est essentiellement un constructeur vide qui ne contient aucun code, par exemple public className() {}
est ce à quoi pourrait ressembler un constructeur par défaut. Puisqu'il n'initialise explicitement aucun attribut, tous les attributs prennent des valeurs par défaut - également appelées valeurs nulles.
Créons manuellement un constructeur pour la classe Mammal
, qui initialise un objet Mammal
avec certaines données :
index.cs
12345678910111213141516171819202122232425262728293031323334353637383940414243444546#pragma warning disable CS0169 // To disable some unnecessary compiler warnings for this example. Using this is not a recommended practice. using System; class Mammal { int age; float weight; // kg public Mammal(int age, float weight) { this.age = age; this.weight = weight; } } class Dog : Mammal { string breed; public void speak() { Console.WriteLine("Woof!"); } } class Cat : Mammal { string furPattern; public void speak() { Console.WriteLine("Meow!"); } } class ConsoleApp { static void Main() { // Creating a "Mammal" object with some data Mammal m1 = new Mammal(10, 42.0f); } }
Si vous essayez de compiler ce programme, des erreurs apparaîtront dans la console. Pour comprendre ces erreurs, il est nécessaire de saisir deux concepts importants liés aux constructeurs.
Le premier est que, dès que vous définissez explicitement un constructeur pour une classe, cette classe ne possède plus de constructeur par défaut. Ainsi, le constructeur défini explicitement devient le constructeur principal de cette classe, qui dans ce cas est :
index.cs
12345public Mammal(int age, float weight) { this.age = age; this.weight = weight; }
Par conséquent, lors de la création d’un nouvel objet, il est toujours nécessaire de fournir les arguments requis du constructeur dans le bon ordre :
index.cs
1234567// Incorrect ways to create 'Mammal', will show an error Mammal m1 = new Mammal(); Mammal m1 = new Mammal(10); Mammal m1 = new Mammal(42.0f); // Correct way to create 'Mammal', will execute fine. Mammal m1 = new Mammal(10, 42.0f);
Deuxièmement, les classes dérivées peuvent également avoir des constructeurs ; cependant, avant que le constructeur d’une classe dérivée ne soit appelé, le constructeur de la classe de base (parente) est également appelé :
index.cs
1234567891011121314151617181920212223242526272829303132333435#pragma warning disable CS0169 // To disable some unnecessary warnings, using this is not a recommended practice. using System; class Mammal { int age; float weight; // kg // No attribute is initialized explicitly in this constructor // Hence, all attributes will take up "zero" values // It is similar to a "default" constructor except it outputs a message public Mammal() { Console.WriteLine("Mammal Constructor Called"); } } class Dog : Mammal { string breed; public Dog() { Console.WriteLine("Dog Constructor Called"); } } class ConsoleApp { static void Main() { Dog myDog = new Dog(); } }
Lorsque vous exécutez ce code, vous constatez que la méthode WriteLine()
du constructeur de 'Mammal', qui est la classe parente, est automatiquement appelée. Cela signifie qu'il s'agit d'une règle selon laquelle le constructeur de la classe de base (également appelé constructeur de base) est toujours appelé avant le constructeur de la classe dérivée.
Cette règle s'applique également dans le cas d'une héritage multiniveau :

Dans le schéma ci-dessus, le constructeur de Kitten
appelle le constructeur de Cat
avant le sien, cependant, puisque Cat
est également une classe dérivée, il appelle le constructeur de Mammal
avant le sien, et Mammal
appelle le constructeur de Animal
avant le sien. Ainsi, le premier constructeur exécuté est celui de la super classe — c'est-à-dire le constructeur de la classe Animal
, puis l'exécution descend dans la hiérarchie.
Si le constructeur de la classe parente ne prend aucun argument, il est automatiquement appelé par le compilateur, c'est la raison pour laquelle le constructeur de 'Mammal' dans l'exemple ci-dessus a été appelé automatiquement. Cependant, examinons à nouveau le code erroné :
index.cs
12345678910111213141516171819202122232425262728293031323334353637383940414243using System; class Mammal { int age; float weight; // kg public Mammal(int age, float weight) { this.age = age; this.weight = weight; } } class Dog : Mammal { string breed; public void speak() { Console.WriteLine("Woof!"); } } class Cat : Mammal { string furPattern; public void speak() { Console.WriteLine("Meow!"); } } class ConsoleApp { static void Main() { // Creating a "Mammal" object with some data Mammal m1 = new Mammal(10, 42.0f); } }
Dans le code ci-dessus, deux erreurs apparaissent, indiquant essentiellement que les constructeurs de base n'ont pas été appelés manuellement — puisqu'ils nécessitent des arguments, il faut les appeler explicitement. La syntaxe de base pour appeler manuellement le constructeur de la classe parente est la suivante :
index.cs
12345678910class DerivedClassName : ParentClassName { // ... attributes // ... methods public DerivedClassName(int arg1, int arg2, ...) : base(arg1, arg2, ...) { // code here } }
Exemple :
index.cs
1234567891011121314151617181920212223242526272829303132using System; class ExampleParentClass { int value1; int value2; public ExampleParentClass(int value1, int value2) { this.value1 = value1; } } class ExampleDerivedClass : ExampleParentClass { int value3; // The value1 and value2 arguments are passed to the base class's contructor public ExampleDerivedClass(int value1, int value2, int value3) : base (value1, value2) { this.value3 = value3; } } class ConsoleApp { static void Main() { var testObject = new ExampleDerivedClass(5, 7, 9); } }
En utilisant cette syntaxe, il est possible de transmettre toutes les données requises au constructeur Mammal
via les constructeurs Cat
et Dog
afin de corriger l’erreur rencontrée précédemment :
index.cs
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758using System; class Mammal { int age; float weight; // kg public Mammal(int age, float weight) { this.age = age; this.weight = weight; } } class Dog : Mammal { string breed; public Dog(int age, float weight, string breed) : base(age, weight) { this.breed = breed; } public void speak() { Console.WriteLine("Woof!"); } } class Cat : Mammal { string furPattern; public Cat(int age, float weight, string furPattern) : base(age, weight) { this.furPattern = furPattern; } public void speak() { Console.WriteLine("Meow!"); } } class ConsoleApp { static void Main() { // Creating a "Mammal" object with some data Mammal m1 = new Mammal(10, 42.0f); // Creating a "Dog" object with some data Dog d1 = new Dog(10, 42.5f, "Dobermann"); Console.WriteLine("Executed Successfully"); } }
Une autre caractéristique importante des constructeurs est la possibilité de les surcharger, tout comme pour toute autre méthode. Il est possible de créer plusieurs constructeurs avec un nombre d’arguments différent :
index.cs
12345678910111213141516171819202122232425class Mammal { int age; float weight; // kg // 1st constructor public Mammal() { // We leave it empty for this example // Since it's empty, it mimics the "default" constructor } // 2nd constructor public Mammal(int age) { this.age = age; } // 3rd constructor public Mammal(int age, float weight) { this.age = age; this.weight = weight; } }
Dans ce cas, la classe Mammal
possède 3 constructeurs. Il est donc possible d'initialiser ou de créer un objet mammifère de 3 manières différentes, et le compilateur choisira quel constructeur appeler en fonction du nombre et du type d'arguments :
index.cs
1234// All Correct var m1 = new Mammal(); var m2 = new Mammal(10); var m3 = new Mammal(10, 42.5f);
Cela signifie également que vous pouvez appeler n'importe lequel des 3 constructeurs depuis les constructeurs de la classe dérivée. Par exemple, toutes les options suivantes sont valides :
index.cs
123456789101112131415161718// Using 3rd base constructor public Dog(int age, float weight, string breed) : base(age, weight) { this.breed = breed; } // Using 2nd base constructor public Dog(int age, string breed) : base(age) { this.breed = breed; } // Using 1st base constructor // If the base constructor has no arguments then it is automatically called (similar to the default constructor), so we don't necessarily need to write 'base()' public Dog(string breed) { this.breed = breed; }
Assemblons les deux extraits ci-dessus et ajoutons quelques instructions Console.WriteLine
afin d'observer dans quel ordre les constructeurs sont exécutés, pour constater les résultats de manière pratique :
index.cs
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394using System; class Mammal { int age; float weight; // kg // 1st Constructor public Mammal() { // We leave it empty for this example // Since it's empty, it mimics the "default" constructor // The attributes are initialized with zero values Console.WriteLine("Mammal - Constructor 1 Called"); } // 2nd Constructor public Mammal(int age) { this.age = age; Console.WriteLine("Mammal - Constructor 2 Called"); } // 3rd Constructor public Mammal(int age, float weight) { this.age = age; this.weight = weight; Console.WriteLine("Mammal - Constructor 3 Called"); } } class Dog : Mammal { string breed; public Dog() { Console.WriteLine("Dog - Constructor 1 Called"); } // Using 1st Mammal constructor // We don't necessarily need to write 'base()' in this case // It automatically finds and calls the constructor with no arguments public Dog(string breed) { this.breed = breed; Console.WriteLine("Dog - Constructor 2 Called"); } // Using 2nd Mammal constructor public Dog(int age, string breed) : base(age) { this.breed = breed; Console.WriteLine("Dog - Constructor 3 Called"); } // Using 3rd Mammal constructor public Dog(int age, float weight, string breed) : base(age, weight) { this.breed = breed; Console.WriteLine("Dog - Constructor 4 Called"); } public void speak() { Console.WriteLine("Woof!"); } } class ConsoleApp { static void Main() { // Creating a "Mammal" object using different constructors Mammal m1 = new Mammal(10, 42.0f); Mammal m2 = new Mammal(10); Mammal m3 = new Mammal(); Console.WriteLine("----------"); // Seperator, for ease of reading output // Creating a "Dog" object using different constructors Dog d1 = new Dog(10, 42.0f, "Dobermann"); Console.WriteLine(""); Dog d2 = new Dog(10, "Dobermann"); Console.WriteLine(""); Dog d3 = new Dog("Dobermann"); Console.WriteLine(""); Dog d4 = new Dog(); } }
Maintenant que vous connaissez les différentes fonctionnalités de l'héritage, il est également important de savoir comment et quand les utiliser correctement. Voici quelques points à garder à l'esprit lors de la conception d'une structure de classe basée sur l'héritage :
Équilibre entre simplicité et flexibilité : La surcharge de constructeurs permet d'avoir plusieurs constructeurs acceptant différents types d'arguments, mais en abuser peut rendre le code plus complexe et difficile à maintenir. Il est recommandé de garder le code de la classe court, concis et pratique. Évitez de créer trop de constructeurs pour une classe afin de maintenir un équilibre entre simplicité et flexibilité.
Garder les constructeurs simples : Les constructeurs doivent principalement servir à initialiser un objet avec des données de base. Il est conseillé d'éviter tout traitement inutile et toute logique complexe à l'intérieur d'un constructeur. Si un calcul ou une logique est nécessaire, il est préférable de créer une méthode séparée pour cela.
;Mauvaise pratique:;
index.cs
123456789101112131415161718192021222324252627class Customer { string name; string accountType; double balance; public Customer (string name, string accountType, double balance) { this.name = name; this.accountType = accountType; if (accountType == "Savings") { // Plus 1 Percent this.balance = balance + balance * 0.01; } else if (accountType == "HighYieldSavings") { // Plus 5 percent this.balance = balance + balance * 0.05; } else { this.balance = balance; } } }
Bonne pratique :
index.cs
123456789101112131415161718192021222324252627282930class Customer { string name; string accountType; double balance; public Customer (string name, string accountType, double balance) { this.name = name; this.accountType = accountType; this.balance = balance; monthlyInterest(); } // This method might be used in other places too private void monthlyInterest() { if(accountType == "Savings") { // Plus 1 Percent balance += balance * 0.01; } else if(accountType == "HighYieldSavings") { // Plus 5 percent balance += balance * 0.05; } } }
Initialiser les attributs importants : il est nécessaire d'initialiser tous les attributs importants d'un objet avec des valeurs correctes afin de garantir leur bon fonctionnement, même s'il s'agit d'un constructeur sans arguments.
Mauvaise pratique :
index.cs
123456789101112131415public class Car { private string brand; private string model; private int year; private double price; // Constructor does not initialize important attributes // It is also generally not a good idea to have constructors without any arguments if they're not needed. public Car() { // No initialization of attributes Console.WriteLine("Car Created"); } }
Bonne pratique :
index.cs
123456789101112131415161718192021222324252627282930313233343536373839public class Car { private string brand; private string model; private int year; private double price; // Good: Constructor initializes important attributes // It also checks if the values are correct // In this case the if-else statements are not unnecessary since they are important for ensuring that the object functions correctly. public Car(string brand, string model, int year, double price) { this.brand = brand; this.model = model; // Validate and set the year // The first public car was created in 1886 :) if (year > 1886) { this.year = year; } else { Console.WriteLine("Invalid year. Setting year to default."); this.year = DateTime.Now.Year; // Set to current year as default } // Validate and set the price if (price >= 0) { this.price = price; } else { Console.WriteLine("Invalid price. Setting price to default."); this.price = 0; // Set to a default value } } }
1. Quelle fonctionnalité permet de créer plusieurs constructeurs pour une classe ?
2. Vous pourriez avoir besoin d'utiliser l'un des concepts des sections précédentes dans ce quiz. Le code ci-dessous comporte une erreur aux lignes 15 et 16. Examinez attentivement le code et décidez quelle est la correction la plus efficace pour cette erreur :
Merci pour vos commentaires !