SI4 - Support C#
SI4 - Support C#
SI4 - Support C#
Support de cours C#
SUPPORT DE
COURS C#
SI4 - SLAM2
Date Révision
Août 2018 Création (v95)
09/10/2018 Simplification (suppression algorithmie)
22/11/2018 Ajout exemple Split() + toString(a,b) + autres conversions + affichage avec {0} + saisie
11.4.3 Utilisation.............................................................................................................47
11.4.4 Exemple de codage (TD à reproduire)................................................................47
11.4.5 Exercice...............................................................................................................49
12 Les classes abstraites et interfaces...................................................................................50
12.1 Classe abstraite..........................................................................................................50
12.1.1 Exercice...............................................................................................................51
12.1.2 Exercice...............................................................................................................51
12.2 Les interfaces..............................................................................................................51
13 Annexes..............................................................................................................................53
13.1 Les caractères d'échappements.................................................................................53
1 PROGRAMMATION C#
namespace HelloWorld
{
class Program
{
static void Main(string[] args) {
Console.WriteLine("Hello World");
Console.ReadKey();
}
}
}
Ce code est constitué de plusieurs parties, dont certaines resteront faiblement décrites pour le
moment :
1.1.1 COMMENTAIRES /* ET */
Pour C#, les lignes comprises entre /* et */ ne sont pas lues : cela permet au programmeur de placer
des commentaires avant un code complexe, ou bien décrire rapidement ce que fait l’application.
Il est important de comprendre qu’il faut une convention d’écriture commune à tous les
programmeurs. On utilise donc des balises ouvrantes et fermantes, un peu comme en français, les
symboles ‟ et ” indique que le texte contenu entre les deux symboles et dit à haute voix par exemple.
Sur une ligne seulement (ou bien après une instruction) C# accepte le double symbole //.
1.1.2 BLOCS { ET }
L’utilisation de blocs, permet à l’interpréteur C# de comprendre que l’ensemble des instructions
comprises entre { et } vont ensemble et constituent un bloc non-sécable.
Ici, namespace contient tout le programme qui n’est constitué que d’une seule classe ‘Program’ qui
elle-même ne contient qu’une fonction ‘Main’.
Cette structure permet de découper un programme en section logique (on regroupe ensemble, les
classes et fonctions qui agissent de manière similaire ou qui ont un lien commun sur les données ou
les interfaces). Si vous ne comprenez pas cette phrase, c’est tout à fait normal lorsque l’on commence
à programmer avec un langage comme celui-ci…
1.2 EN RÉSUMÉ
Le schéma ci-après donne un exemple d’analogie possibles
En cliquant sur ► Démarrer, une console doit s’ouvrir et afficher notre message.
Voici quelques questions pour valider votre compréhension et approfondir vos connaissances…
Réponses :
Faux c’est point-virgule ; Faux c’est regroupé dans un bloc ; Vrai ; Faux car contient un symbole (‘) ; Faux using
intègre les bibliothèques ; Vrai.
2 TYPES DE DONNÉES
Dans les langages de programmation typés, c’est le programmeur qui choisit l’espace de valeurs pour
les variables. En Python ou PHP (qui ne sont pas typés), l’interpréteur suppose le type
automatiquement. En C#, C++, Java et de nombreux autres langages, le programmeur peut optimiser
son code (pour le rendre plus performant en vitesse et occupation mémoire) en choisissant lui-même
le type de ses variables.
Les types qui sont rayés n’existent pas en C# mais sont présents en C#.
2.1.1 DÉCLARATION
int unEntier;
char uneLettre;
2.1.2 AFFECTATION
unEntier = 25;
uneLettre = 'c';
Cependant, la déclaration ne doit se faire qu'une fois : il ne faut donc pas le faire dans une boucle.
2.2.1 DÉCLARATION
Int32 unEntier;
String unMot;
Boolean monDrapeau;
2.2.2 AFFECTATION
unEntier = 25;
unMot = "Bonjour le monde";
monDrapeau = true; // ne peut prendre que true ou false
En effet, certaines méthodes ne permettent que l’utilisation d’objet (comme les méthodes de la classe ArrayList). Il était
nécessaire d’encapsuler les types primitifs dans un objet. Par exemple :
int myInt = 5 ;
list.add(new Int32(myInt)) ; // ce mécanisme de boxing est relativement lourd. Les classes conteneurs facilitent tout.
Les constantes sont utilisées surtout par les programmeurs et n'ont pas d'utilité pour l'utilisateur.
Cela est utile pour créer des variables contenant des objets dont on ne connaît pas le type.
Pour synthétiser, un byte est inclus dans un short qui est inclus dans un int qui est inclus dans un long qui est inclus dans
un float qui est inclus dans un double. Un char sera inclus uniquement à partir d’un int, car il n’a pas de bit de signe.
Cette méthode est plus efficace que la méthode convert, car si l'utilisateur saisit des caractères ou une
valeur non numérique, la méthode TryParse() renverra VRAI si la conversion est possible ou FALSE
dans le cas contraire, mais surtout, renvoie un résultat dans la variable après 'out'. On évite donc le
plantage de l'application.
Considérez que le mot clé out indique à la méthode (ou fonction) qu'elle doit modifier directement la
variable elle-même.
L'astuce est que C# détecte que le résultat est une chaîne, il convertit tout seul les nombres qu'il
trouve.
3 LES OPÉRATIONS
Les priorités sont respectées (multiplication et division passent avant l’addition et la soustraction)
int randomNumber;
Random RNG = new Random();
d = RNG.Next(1,10);
Attention à ne pas confondre opérations binaires et comparateurs (&&, ||, !=, ==, ≥=, <=... )
Voir https://msdn.microsoft.com/en-us/library/system.string(v=vs.110).aspx
Cependant, la méthode toString() est très puissante et permet des conversions de nombre en chaîne
binaire ou hexadécimale (le premier paramètre est la valeur à convertir, le deuxième est la base de
calcul) :
int a = 255;
int b = 128;
4 LES TABLEAUX
Un tableau est un ensemble de variables de même type dans une quantité définie.
Chaque case du tableau est numérotée, en partant de 0 : un tableau contenant 10 valeurs aura les
numéros de cases de 0 à 9 (on parle de l’indice de cellule).
4.1.1 DÉCLARATION
0 1 2 3 4 5
1995 1996 1997 1998 2000 2001
Une autre déclaration (pour un tableau de chaîne vide par exemple) est la suivante :
String[] monTableau = new String[9];
String[] autreTableau = new String[9];
Ces deux tableaux contiendront donc 10 chaînes de caractères (l’index commence à 0 !).
int tailleTableau = autreTableau.length;
Enfin, il est possible d’utiliser des tableaux à plusieurs dimensions (comme pour la bataille navale) :
byte[,] monTableau = new byte[5,4];
int[,] autreTableau2D = {{1,2,3},{4,5,6},{7,8,9}};
Le premier tableau est une grille de 10x10 éléments tandis que le deuxième tableau contient 3x3
éléments. Il faut donc voir les tableaux à dimensions multiples comme des tableaux de tableau.
4.1.2 AFFECTATION
5.1.1 AFFICHAGE
• System est la classe utilisée pour l’affichage sur une console. Il n’est pas nécessaire de la
déclarer si "using System" est placé en entête du programme.
• Console est l’objet dans cette classe, qui gère les sorties : ici, l’objet console est l’écran
principal de la console. Il existe un objet error qui permet de noter les erreurs. L’objet in est
utilisé pour récupérer les flux du clavier.
• WriteLine() est la méthode qui s’applique sur l’objet out : cette méthode envoie à cet objet les
données comprises entre ses parenthèses. Il existe aussi Write() qui ne fait pas de saut de
ligne.
Exemple :
Console.writeLine("Coco !"); // affichera 'Bonjour Coco !' sur la même ligne
Console.Error.WriteLine("Un problème"); // affichera 'Un problème' aussi...
Affichera le résultat suivant (le salaire est formaté pour afficher un nombre en devise) :
5.1.2 DEBUG
Il existe une classe en C# qui permet d’afficher des informations dans la console du débogueur. Pour
cela, il faut activer la bibliothèque correspondante :
using System.Diagnostics ;
Enfin, pour visualiser la console dans Visual Studio, utilisez la séquence de touches CTRL+Alt+O
D’autres options sont disponibles pour une meilleure mise en forme, comme :
Debug.Indent() ;
Debug.Unindent() ;
L’intérêt de cette solution, est de ne pas polluer la console du programme principale, ou bien d’être
utilisable dans les programmes de type WinForm.
5.1.3 SAISIE
Le type pour récupérer le résultat de ReadKey() est un type objet. Nous verrons cela plus tard.
Il n’existe pas de lecture de clavier caractère par caractère qui ne serait pas bloquant.
Il est cependant possible de simplifier les deux lignes par imbrication des fonctions :
int valeurNombre = Convert.toInt32(Console.ReadLine);
Toutefois, cette méthode présente un inconvénient car, le programme ne saura pas traiter la
conversion de caractères non numériques (autres que de 0 à 9 et le séparateur décimal) : il plantera.
Cette fonction n'est cependant par exempte de problème et peut sembler complexe pour une simple
vérification de texte. Vous pouvez la réutiliser mais nous verrons un autre moyen pour éviter le
plantage du programme.
En réalité, un plantage ne signifie pas que l'ordinateur a fait une erreur, mais plutôt qu'il ne sait pas comment réagir face à
un événement imprévu. Ici, la conversion d'une chaîne en un nombre peut poser problème si la chaîne contient des
caractères alphabétiques… et plutôt que faire une mauvaise conversion, le comportement du langage est d'arrêter le
traitement.
Un peu comme un employé qui viendrait interrompre son supérieur pour demander la solution à prendre, on dit que le
programme lève une exception !
5.2 FICHIERS
L’astuce ci-dessus nous amène à nous intéresser à la lecture et l’écriture de fichier.
Comme évoqué précédemment, pour C#, la plupart des périphériques sont considérés comme des
flux entrants et sortants. Cela signifie que si le flux n’est pas mémorisé, les données transmises sont
perdues (un peu comme une chaîne en direct : si vous êtes absent de l’écran, les informations sont
perdues).
Comme la plupart des périphériques acceptent les entrées et les sorties, cela multiplie par deux les
flux et buffets à déclarer.
Attention, la lecture d’un flux vide entraîne la génération d’une exception qui bloque l’exécution du programme.
Ainsi, la plupart du temps (et c’est aussi vrai en Java), il faudra ouvrir le flux et ouvrir un buffet :
1. Ouvrir le flux du fichier
2. Ouvrir le buffet du flux du fichier
3. Lire/Écrire dans le buffet
4. Fermer le buffet
5. Fermer le flux
Voici donc un exemple de code pour lire un fichier texte, à copier tel quel pour le moment :
using System;
using System.IO;
using System.Text;
namespace FileReadExample
{
class Program
{
static void Main(string[] args) {
FileStream monFlux = null; // Créer un objet flux (en direct)
StreamReader reader = null; // Créer un objet lecteur de flux (bufferise)
String fileContent = "";
try {
// Ouverture
monFlux = File.OpenRead(@"e:\test.txt");
reader = new StreamReader(monFlux, Encoding.UTF8);
// Lecture
Console.WriteLine("Votre fichier contient : ");
fileContent = reader.ReadToEnd();
Console.WriteLine(fileContent);
}
catch (Exception ex) {
Console.WriteLine("Erreur de lecture !"+ex.Message);
}
finally {
// Fermeture
if (reader != null) {
reader.Dispose(); // Fermer le buffer (libère sa mémoire)
}
if (monFlux != null) {
monFlux.Dispose(); // Fermer le fichier (libère le canal)
}
Console.Write("** Appuyez sur une touche **");
Console.ReadKey();
}
}
}
}
namespace FileReadExample
{
class Program
{
static void Main(string[] args) {
FileStream monFlux = null; // Créer un objet flux (en direct)
StreamWriter writer = null; // Créer un objet de flux (bufferise)
try {
// Ouverture
monFlux = File.Open(@"e:\testwrite.txt", FileMode.Append);
writer = new StreamWriter(monFlux);
// Lecture
Console.WriteLine("Écriture réussi dans e:\\testwrite.txt ");
writer.WriteLine("Hello World pour les fichiers :");
}
catch {
Console.WriteLine("Erreur d'écriture !");
}
finally {
// Fermeture
if (writer != null) {
writer.Dispose(); // Fermer le buffer (libère sa mémoire)
}
if (monFlux != null) {
monFlux.Dispose(); // Fermer le fichier (libère le canal)
}
Console.Write("** Appuyez sur une touche **");
Console.ReadKey();
}
}
}
}
et le résultat :
6 EXERCICE
7 BOUCLES ET CONDITIONS
Comme dans d’autres langages, C# propose un ensemble d’instructions pour créer des boucles et
permettre des choix à l’aide de conditions.
7.1 BOUCLES
Il existe 3 boucles connues (répétition, test avant de commencer la boucle et test en fin de boucle).
On peut aussi créer une boucle infinie comme ceci (sortie possible avec une instruction ‘break’) :
for (;;) {
Console.writeLine("ne s'arrête jamais... ahahah !") ;
}
Enfin, lorsqu’on a un tableau ou une liste d’objet, on peut la parcourir automatiquement (foreach)
int[] maTable1 = { 3, 14, 1, 59, 2, 65 };
Console.WriteLine("Taille de la table = " + maTable1.Length);
foreach (int cpt in maTable1) {
Console.Write(":" + cpt + " "); //cpt prend les valeurs 3 puis 14 puis 1, 59...
}
Il est possible de sortir d’une boucle sans que la condition ne soit modifiée, par l’utilisation de l’instruction break !
int t=0;
while (t < 10) {
if (t = 5) {
break;
}
t++;
}
7.2 CONDITIONS
Il y a deux types de conditions :
• les IF, ELSE IF, ELSE
• les SWITCH, CASE
Il y a cependant un impératif : ajouter une instruction ‘break’ avant chaque nouveau bloc ‘case’, sinon
dès qu’une condition est réalisée, tous les blocs suivants sont exécutés.
Essayez le programme précédent en enlevant les mots-clés ‘break’. Le résultat est-il cohérent ?
D’autre part, en C#, la gestion des plages (intervalles) n’est pas intuitive ! Le code le plus proche est le
suivant :
switch (num) {
case 1: case 2: case 3: case 4: case 5:
Console.writeLine("testing case 1 to 5");
break;
case 6: case 7: case 8: case 9: case 10:
Console.writeLine("testing case 6 to 10");
break;
default:
//
}
Les utilisateurs de Pascal et Purebasic seront surpris du manque de souplesse mais PHP et C#
fonctionnent de la même manière que C#. Enfin, il n’y a pas de switch/case en Python.
8 LES FONCTIONS
Les fonctions simplifient et fiabilisent le codage. En effet, effectuer les mêmes actions plusieurs fois à
la suite peut se faire dans une boucle. Effectuer les mêmes actions à des moments différents nécessite
de pouvoir exécuter le même morceau de code à plusieurs endroits du programme.
Voici les deux possibilités :
Avoir plusieurs fois du code identique Appeler plusieurs fois un seul code
Il est évident que la deuxième solution est plus fiable, plus élégance et moins encombrante.
Une fonction est donc un bout de code, utilisable à plusieurs endroits.
Le travail que va faire la fonction Maximum est d’évaluer quel est le nombre le plus grand et de
renvoyer sa valeur.
Évidemment, il est possible de ne pas avoir de paramètre et/ou de ne pas renvoyer de valeur. Une
fonction qui imprime sur l’imprimante par défaut serait (cas fictif) :
public void Imprimer() {
SortirImprimanteVeille() ;
LancerImpressionSpooler() ;
}
Cette fonction – qui appelle deux fonctions – ne renvoie pas de valeur, d’où le mot-clé ‘void’ qui
signifie "vide". L’appel à une fonction sans valeur de retour se fait comme pour la fonction
SortirImprimanteVeille() ou LancerImpressionSpooler() ;
Aide N°1 :
Il faut utiliser une boucle, dont on ne sort que si le résultat est un nombre.
Aide N°2 :
La conversion d’une chaîne de caractère en entier utilise la fonction C# existante :
monNombre = Convert.ToInt16(maChaine)
Aide N°3 :
Il faudra utiliser les exceptions (try… catch) au moment de la conversion (voir chapitre suivant de ce
livre)
Réponse
using System;
namespace SaisirNombre
{
class Program
{
public static Int32 SaisirNombre(Int32 min, Int32 max) {
String maChaine = "";
Int32 nombre=0;
do {
Console.WriteLine("Saisissez un nombre entre "+min+" et "+max);
maChaine = Console.ReadLine();
if (maChaine != "") {
try {
nombre = Convert.ToInt32(maChaine);
}
catch {
maChaine = "";
}
}
} while ((maChaine == "") | (nombre > max) | (nombre < min));
return nombre;
}
9 LES EXCEPTIONS
C# fournit un moyen de contrôle des erreurs lors du déroulement des applications. Cette solution se
faisant au détriment de la performance et nécessitant du code supplémentaire, il est fréquent que
seules les parties sensibles du code soient protégées.
Voici les classes des objets liés aux erreurs fréquentes (par exemple, la lecture d’un index de tableau
au-delà de la taille maximale du tableau générera une exception "ArrayIndexOutOfBounds").
Ici, le programme ne traitera que cette erreur, mais il est possible de traiter chaque erreur (ou
exception) différemment : c’est l’ordre des catch {…} qui déterminera le premier traitement.
Il est également possible de récupérer le message d’erreur de l’exception, comme le montre le code
ci-dessous :
catch (Exception ex) {
Console.WriteLine("Erreur ! " + ex.Message);
}
Cette programmation très séquentielle n’est pas celle utilisée sur les systèmes d’exploitation
graphiques.
10.1 FONCTIONNEMENT
Dans les OS modernes, c’est ce dernier qui gère tous les événements : le système "prête" des
ressources aux programmes. Une fenêtre, un champ de saisie, un bouton… ces éléments sont dessinés
et gérés par l’OS !
Dès lors, chaque clic, chaque action de l’utilisateur est enregistré par le système :
Lorsqu’il y a un événement qui concerne l’application, l’OS lui envoie le numéro de l’événement : le
programmeur décide s’il doit réagir à cet événement. L’avantage est qu’une application qui n’est pas
utilisée ne consommera pas de puissance à sa propre surveillance.
En C#, Visual Studio nous propose un éditeur graphique de fenêtre et masque une partie du codage.
Il faut comprendre la philosophie d’usage : et pour cela, parler légèrement du modèle MVC. Il s’agit d’un modèle qui
permet de simplifier le développement, en séparant la vue (les fenêtres, l’affichage), le contrôleur (les interactions de
l’utilisateur : clic, saisie au clavier, déplacement de souris…) et le modèle de stockage des données (une base, un fichier, la
mémoire…). MVC signifie Modèle – Vue – Contrôleur.
10.2.2.1 PROGRAM.CS
Il contient l’appel de la fenêtre graphique. Comme c’est une programmation événementielle, le
programme devient multi-tâche (il accepte notamment d’être géré par le système).
Visual Studio Sharp Develop
[STAThread] [STAThread]
static void Main() { private static void Main(string[] args) {
Application.EnableVisualStyles(); Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false); Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new Form1()); Application.Run(new MainForm());
} }
10.2.2.2 FORM.DESIGNER.CS
C’est le fichier qui contient la construction de la fenêtre. On y trouve notamment la fonction (on dira
"méthode") qui génère les composants de manière procédurale.
En effet, si vous devez créer 40 composants identiques (imaginez une application contenant un champ
par jour de la semaine), dessiner ces composants manuellement est fastidieux. La syntaxe utilisée ici,
permettra de générer dans une méthode conçue par le développeur, les composants répétitifs.
private void InitializeComponent() {
this.textBox1 = new System.Windows.Forms.TextBox();
this.button1 = new System.Windows.Forms.Button();
this.SuspendLayout();
//
// textBox1
//
this.textBox1.Location = new System.Drawing.Point(32, 29);
this.textBox1.Name = "textBox1";
this.textBox1.Size = new System.Drawing.Size(246, 20);
this.textBox1.TabIndex = 0;
//
// button1
//
this.button1.Location = new System.Drawing.Point(215, 70);
this.button1.Name = "button1";
this.button1.Size = new System.Drawing.Size(62, 31);
this.button1.TabIndex = 1;
this.button1.Text = "Cliquez ici";
this.button1.UseVisualStyleBackColor = true;
//
// Form1
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(339, 131);
this.Controls.Add(this.button1);
this.Controls.Add(this.textBox1);
this.Name = "Form1";
this.Text = "Form1";
this.ResumeLayout(false);
this.PerformLayout();
Notez que les attributs des composants sont suivis par les propriétés puis les valeurs :
this.button1.Text = "textBox1";
Cette ligne signifie que pour le composant button1, on place la valeur "Cliquez ici" dans la propriété
"Text".
10.2.2.3 FORM1.CS
C’est ce fichier qui contiendra les interactions entre l’utilisateur et l’interface du programme. Ainsi, les
lignes suivantes méritent d’être expliquées :
public Form1() {
InitializeComponent();
}
La méthode "Form1()" est publique, donc visible de partout. Elle ne contient qu’une ligne qui appelle
la construction de la fenêtre, dans le fichier Form1.Designer.cs.
La méthode "button1_Click()" correspond aux actions qui seront faites lorsque l’événement
correspondant est appelé. Ici, on affiche une simple boite d’alerte. Notez cependant, que cette
méthode reçoit deux paramètres : l’appelant (sender) et le type d’événement (e).
en effet, lors de l’initialisation des composants, on indique au système (dans le fichier
Form1.Designer.cs) que le programme surveillera les événements qui touchent à ce bouton :
this.button1.Click += new System.EventHandler(this.button1_Click);
Ces informations dépassent le niveau du module SI4 : il s’agit cependant d’une culture générale pour comprendre
comment fonctionne les applications dans les systèmes graphiques fenêtrés.
1 https://www.codeproject.com/Articles/1465/Beginning-C-Chapter-Using-Windows-Form-Controls
11 LES OBJETS
En C#, les objets s’utilisent un peu comme des "super" variables.
Un objet en C#, correspond à un ensemble de variables et des fonctions intégrées. Grâce à une notion
importante appelé encapsulation, il est possible de n’accéder à ces variables qu’au travers de ces
fonctions.
Ainsi, une classe est donc un bloc autonome, et les objets créés à l’aide de cette classe ne peuvent pas
être mis en "pièces détachées".
11.1 VOCABULAIRE
Le langage orienté objet propose un vocabulaire à connaître impérativement.
Ci-contre, la représentation symbolique d’une classe.
Une classe est constituée de membres :
• les attributs : ce sont les variables de la classe. Sauf s’ils sont publics,
les attributs ne sont pas visibles depuis une autre classe (étrangère).
• Les méthodes : ce sont les fonctions ou procédures de la classe. Elles
aussi peuvent être publiques ou privées.
Une classe n’est qu’un patron, un plan d’objet : il faut construire les objets à partir de ce plan, en objet
le terme utilisé : instancier.
Pour instancier une classe, on utilise une méthode de la classe particulière, qui porte le nom de la
classe, et qu’on appelle un constructeur.
11.2 REPRÉSENTATION
Voici un exemple graphique :
La classe
Chat
contient
les
attributs
privés
signifie qu’il n’est possible de modifier ces attributs que par ces méthodes, ce qui est très sécurisant.
11.2.1 INSTANCIATION
Pour créer le chat Félix, il suffit d’instancier la classe Chat et de stocker le résultat dans une "variable"
de type Chat (ce n’est pas un entier, une chaîne… c’est un chat).
La syntaxe d’instanciation est la suivante :
Chat felix = new Chat();
felix.changerNom("Felix");
felix.changerAge(5);
le mot-clé new indique à C# de construire un objet, mais comme pour une maison, l’objet est
initialement vide.
Notez qu’il n’est pas nécessaire de nommer l’objet avec le véritable nom du chat.
Chat chatRoumanet = new Chat() ;
chatRoumanet.changerNom("Pirouette") ;
…
A noter : si le constructeur de la classe n’est pas déclaré explicitement, C# va le créer automatiquement, avec tous les
attributs par défaut.
Astuce : il est possible d’avoir plusieurs constructeurs, à la condition que le nombre d’arguments soit
différents pour chaque constructeur et qu’il soit public (donc visible par tous).
Le mot-clé this permet de préciser à C# qu’il s’agit de l’attribut de l’objet en cours de création,
permettant de ne pas mélanger avec le nom de l’argument transmis :
public Chat() {}
11.3 RÉSUMÉ
(il
s’agit d’une réservation d’espace)
11.4 HÉRITAGE
L’intérêt majeur de la programmation objet est probablement l’héritage : cette notion permet
en effet de profiter des propriétés d’une classe existante et de pouvoir étendre ses capacités.
11.4.1 EXEMPLE
Une clinique vétérinaire qui doit enregistrer des chats et des chiens pourrait avoir deux
classes, comme dans l’image suivante :
11.4.2 DÉCLARATION
La déclaration d’un héritage de classe se fait par l’utilisation du mot ‘extends’ :
public class Chat : Animal {
public void griffer() {
Console.writeLine("Griffé !") ;
}
}
public class Chien : Animal {
public void mordre() {
Console.writeLine("Mordu !") ;
}
}
Contrairement au C++, En C# (et même en Java) une classe ne peut hériter que d’une seule classe.
11.4.3 UTILISATION
Une fois déclarée, la classe s’utilise normalement.
Chat monChat = new Chat();
Chien monChien = new Chien();
Animal maTortue = new Animal();
namespace Animal
{
public class Animal
{
protected String nom;
protected Int16 poids;
protected DateTime naissance;
Ici, naissance, nom et poids (ordre alphabétique) appartiennent bien à la classe Animal dans le fichier
Animal.cs.
La classe Chat étend la classe Animal en ajoutant le miaulement (méthode Miaule()) :
using System;
namespace Animal
{
class Chat : Animal
{
public Chat() {
this.nom = "Minou inconnu";
}
public String Miaule() {
return "Miaou";
}
}
}
namespace Animal
{
Le résultat sera :
11.4.5 EXERCICE
Finissez la classe Chat en ajoutant la méthode griffer(). Cette méthode contient un tirage au hasard
entre 0 et 0.999 et affichera
"le-nom-du-chat a essayé de vous griffer" si le tirage est supérieur à 0.8, sinon
"le-nom-du-chat vous aime bien et ne vous griffe pas".
Créez également la classe Chien en y intégrant la méthode mordre() ayant un comportement similaire
que la méthode griffer().
Pour validation auprès du professeur, envoyez seulement le contenu du répertoire ‘src’ dans un fichier
ZIP.
↔
public Formes() {
couleurForme = 0;
aireForme = 0;
}
public void Remplissage(int color) {
this.couleurForme = color;
}
12.1.1 EXERCICE
Ajoutez une classe ‘Disque’ dont on calculera :
• le périmètre par la formule 2 * PI * valeurCalcul[0]
• l’aire par la formule PI * r²
Pour rappel, valeurCalcul est un tableau mais pour un disque, on n’utilise que le premier élément pour y placer le rayon.
12.1.2 EXERCICE
Ajoutez une classe ‘Rectangle’ dont on calculera :
• le périmètre par la formule (valeurCalcul[0] + valeurCalcul[1])* 2 (P=(a+b)*2)
• l’aire par la formule valeurCalcul[0] * valeurCalcul[1] (A = a * b)
interface IAnimal {
string Name { get; }
void Move();
}
Ici, l’interface ‘Ianimal’ contient un atribut (public) ‘Name’ et une méthode (publique) Move().
On crée notre propre attribut de stockage du nom en privé. Les utilisateurs de la classe ‘Dog’ ne
connaîtront jamais cet attribut et utiliseront ‘Name’ à la place : cela garantit le même usage par tous !
Notez que la modification du nom du chien ne se fera qu’à l’instanciation de la classe : une fois nommé, le chien ne
changera plus de nom.
L’implémentation de la méthode Move() est similaire à une classe abstraite mais n’utilise pas
‘override’. L’oubli de cette implémentation donne lieu à un message clair du compilateur :
L’avantage principal est qu’une classe peut hériter de plusieurs interfaces (alors qu’une classe ne peut
hériter que d’une seule classe).
13 ANNEXES