• Aucun résultat trouvé

IFT 1179 : Programmation en C# A) Classe abstraite (abstract class):

N/A
N/A
Protected

Academic year: 2022

Partager "IFT 1179 : Programmation en C# A) Classe abstraite (abstract class):"

Copied!
13
0
0

Texte intégral

(1)

IFT 1179 : Programmation en C#

A) Classe abstraite (abstract class):

Pourquoi ?

Lors de la conception d'une hiérarchie, on a besoin de créer des classes plus générales d'abord et différer l'implémentation à des étapes plus éloignées quand le comportement est très bien défini. Quand on parle de figure géométrique, il est trop vague pour savoir comment calculer un périmètre, une surface : ces méthodes sont encore abstraites. Il est impossible de réaliser (implémenter) ces méthodes. Par contre, un rectangle est une figure géométrique dont le calcul du périmètre et de la surface est connu, on peut alors implémenter ces méthodes qui sont très concrètes (pas du tout abstraites) pour un rectangle.

classe abstraite : Figure géométrique peut-on calculer :

1) le périmètre de n'importe quelle figure ? non! => ce calcul est abstrait!

2) la surface de n'importe quelle figure ? non! => ce calcul est abstrait!

classe

Parallelogramme

périmètre : Oui

2x(cote1+cote2)

surface : Non encore abstraite

classe Cercle périmètre : Oui

2xMath.Pi x rayon

surface : Oui Math.Pi x rayon

2

classe Triangle périmètre : Oui

côté1+côté2+côté3

surface : Non

classe Rectangle

surface : Oui

longueur x largeur classe concrète

classe

TriangleRectangle

surface : Oui

hauteur x base / 2 classe concrète

En résumé : une classe abstraite est celle qui n'est que partiellement implantée

(2)

using System;

abstract class FigureGeo {

public abstract double Perimetre();

public abstract double Surface();

public override string ToString(){

return string.Format("\nPerimetre : {0, 7:F2}, Surface : {1, 7:F2}", Perimetre(),Surface());

}

}

/* Cette classe est CONCRÈTE car toutes les méthodes sont implénentées (réalisables)

*/

class Cercle : FigureGeo {

private double rayon;

public Cercle(double rayon) { this.rayon = rayon;

}

public override double Perimetre() { return 2 * Math.PI * rayon;

}

public override double Surface() { return Math.PI * rayon * rayon;

}

public override string ToString() {

return "Cercle de rayon : " + rayon +

base.ToString();

}

}

/* Cette classe est encore abstraite car on ne sait pas encore comment calculer la Surface.

*/

abstract class Parallelogramme: FigureGeo {

protected double cote1, cote2;

// on a quand même le droit d'avoir de constructeur public Parallelogramme(double cote1, double cote2) {

this.cote1 = cote1;

this.cote2 = cote2;

}

(3)

// cette méthode est "concrète" ici:

public override double Perimetre() { return 2 * (cote1+cote2);

}

public override string ToString() {

return "Les 2 cotes : " + cote1 + ", " + cote2 + "\n" + base.ToString();

}

}

/* Cette classe est CONCRÈTE car toutes les méthodes sont implémentées (réalisables)

*/

class Rectangle

: Parallelogramme {

public Rectangle(double longueur, double largeur) : base(longueur, largeur)

{ }

public override double Surface() { return cote1*cote2;

}

public override string ToString() {

return "En tant qu'un rectangle : " + base.ToString();

} }

class Abstraite1 {

static void Main (string[] args) {

Cercle c = new Cercle(10.0);

Console.WriteLine(c);

Rectangle r = new Rectangle(6.8, 3.2);

Console.WriteLine("Infos du rectangle r :\n" + r);

} }

/* Exécution:

Cercle de rayon : 10

Perimetre : 62,83, Surface : 314,16 Infos du rectangle r :

En tant qu'un rectangle : Les 2 cotes : 6,8, 3,2

Perimetre : 20,00, Surface : 21,76 Press any key to continue

*/

(4)

Exercices :

Programmez la classe abstraite Triangle et sa classe dérivée, concrète TriangleRectangle .

Remarques :

1. On n’a pas le droit d’instancier (avec new) un objet d’une classe abstraite;

2. Une classe abstraite peut contenir des méthodes non abstraites;

3. Une classe abstraite peut contenir des constructeurs pour faire appeler par ses classes dérivées ( avec base(. . .) )

4. Une méthode abstraite est automatiquement virtuelle (mais on n’a pas le droit de fournir ce mot virtual sur l’en-tête). Ces méthodes

abstraites peuvent être toutes ou en partie redéfinies (override) dans une classe dérivée.

Réflexions :

Dans tous les jeux de cartes, on devrait (entre autres) distribuer des cartes. La méthode distribuer varie d’un jeux de cartes à un autre jeux.

Cette méthode est donc abstraite. La classe JeuxDeCartes est alors une

classe abstraite.

(5)

B) Interface :

Pourquoi ?

Le C# (et aussi Java) ne supporte pas l'héritage multiple comme C++ :

Classe de base

A1

Classe de base

A2

Classe de base

A3

etc …

classe dérivée en C++

B

En C# une classe n'a pas le droit d'hériter directement deux classes de base. Par contre, C# permet à une classe d'être dérivée d'une seule classe de base mais implémente une ou plusieurs interfaces.

Classe de base en

C#

A

interface I1

interface

I2 etc

sous-classe B dérivée de A implémente I1, I2, etc

De plus, une interface contient souvent ses méthodes abstraites qui seront réalisées dans

les classes qui implémentent cette interface.

(6)

Premier exemple :

/* Fichier Interface1.cs

* Premier exemple d'une interface (ici IFigure) */

using System;

// cette interface comporte deux méthodes à implémenter // dans Cercle, Carre, ...

interface IFigure

{ double Perimetre();

double Surface();

}

// la classe Cercle IMPLÉMENTE l'interface IFigure

class Cercle: IFigure {

private double rayon;

public Cercle(double rayon) { this.rayon = rayon;

}

public Cercle() {

}

public double Perimetre() { return 2 * Math.PI * rayon;

}

public double Surface() {

return Math.PI * rayon * rayon;

}

}

class Carre : IFigure {

private double cote;

public Carre(double cote) { this.cote = cote;

}

public Carre() {

}

public double Perimetre() { return 4 * cote;

(7)

}

public double Surface() { return cote*cote;

}

}

class Interface1 {

static void Main(string[] args) {

IFigure[] fig = { new Cercle(10.2),

new Carre(2.8), new Carre(6.5) };

double somme = 0;

foreach (IFigure figure in fig)

somme += figure.Surface();

Console.WriteLine("Surface totale {0, 8:F2}", somme);

}

}

/* Execution:

Surface totale 376,94 Press any key to continue

*/

(8)

Exemple 2 : Peut-on trier n’importe quel tableau avec une même méthode de tri ?

using System;

class Personne : IComparable {

protected string nomPre ;

protected double taille, poids;

protected char sexe;

public Personne(string nomPre, double taille, double poids, char sexe)

{

this.nomPre = nomPre;

this.taille = taille;

this.poids = poids;

this.sexe = sexe;

}

public Personne(string nomPre, double taille, double poids) : this (nomPre, taille, poids, 'F')

{ }

public Personne() {

}

public override string ToString() {

return string.Format("{0,-20:S} {1,6:F2} {2, 6:F2}

{3,10:S}", nomPre, taille, poids, (sexe == 'F' ? "feminin":"masculin"));

}

public int CompareTo(object obj) {

Personne autre = (Personne) obj;

return nomPre.ToUpper().CompareTo( autre.nomPre.ToUpper() ) ; }

}

class Station : IComparable {

private string nom; // nom de la station private int rang2003, // rang en 2003

freq2004; // nb. de passagers aux tourniquets en 2004

// un constructeur possible public Station(string nom, int rang, int freq2004) {

this.nom = nom;

rang2003 = rang;

(9)

this.freq2004 = freq2004;

}

// un autre constructeur possible public Station(string chaine)

{

char[] separateurs = new char[] {'(', ')'};

string[] infosMetro = chaine.Split(separateurs, 3);

nom = infosMetro[0];

rang2003 = int.Parse(infosMetro[1]);

freq2004 = int.Parse(infosMetro[2]);

}

// un constructeur sans paramètre public Station()

{ }

// redéfinition ToString pour afficher une station public override string ToString()

{

return String.Format("{0, -35:S} {1,4:D} {2, 12:N0}", nom, rang2003, freq2004 );

}

public int CompareTo(object obj) {

Station autre = (Station) obj;

return freq2004 - autre.freq2004;

} }

class Interface2 {

static void Permuter(IComparable[] tableau, int i, int indMin) {

IComparable tempo = tableau[i];

tableau[i] = tableau[indMin];

tableau[indMin] = tempo;

}

static void Trier(IComparable[] tableau, int nbElem) {

for(int i = 0; i < nbElem-1; i++) {

int indMin = i;

for (int j = i+1; j < nbElem ; j++)

if (tableau[j].CompareTo(tableau[indMin]) < 0)

indMin = j;

if (indMin != i)

(10)

}

static void Afficher(IComparable[] tableau, string mess) {

Console.WriteLine("\nContenu du tableau des " + mess + ":\n");

for (int i = 0; i < tableau.Length; i++)

Console.WriteLine("{0,3:D}) {1}", i, tableau[i]);

Console.WriteLine();

}

static void Main(string[] args) {

Personne[] pers = {

new Personne("Tremblay Jacques", 1.72, 78.9, 'M'), new Personne("Charbonneau Lise", 1.83, 65.1, 'F'), new Personne("Ferland Pierre", 1.58, 80.7, 'M')} ;

Trier(pers, pers.Length);

Afficher(pers, "personnes apres le tri selon les noms");

Station[] stat = {

new Station("COTE-VERTU(9)6387345"), new Station("DE LA SAVANE(65)690673"), new Station("JEAN-TALON(11)5021175"),

new Station("COTE-DES-NEIGES(26)3509564") };

Trier(stat, stat.Length);

Afficher(stat, "stations apres le tri selon la frequence en 2004");

} }

/* Exécution:

*

Contenu du tableau des personnes apres le tri selon les noms:

0) Charbonneau Lise 1,83 65,10 feminin 1) Ferland Pierre 1,58 80,70 masculin 2) Tremblay Jacques 1,72 78,90 masculin

Contenu du tableau des stations apres le tri selon la frequence en 2004:

0) DE LA SAVANE 65 690 673 1) COTE-DES-NEIGES 26 3 509 564 2) JEAN-TALON 11 5 021 175 3) COTE-VERTU 9 6 387 345 Press any key to continue

*/

(11)

Exemple 3 : Devrait-on toujours écrire des méthodes pour le tri et la recherche dans un tableau trié ?

/* Fichier Interface3.cs */

using System;

using System.IO;

class Station : IComparable {

private string nom; // nom de la station private int rang2003, // rang en 2003

freq2004; // nb. de passagers aux tourniquets en 2004

// un constructeur possible

public Station(string nom, int rang, int freq2004) {

this.nom = nom.ToUpper();

rang2003 = rang;

this.freq2004 = freq2004;

}

// un autre constructeur possible public Station(string chaine)

{

char[] separateurs = new char[] {'(', ')'};

string[] infosMetro = chaine.Split(separateurs, 3);

nom = infosMetro[0];

rang2003 = int.Parse(infosMetro[1]);

freq2004 = int.Parse(infosMetro[2]);

}

// un constructeur sans paramètre public Station()

{ }

// pour afficher les infos d'une station public override string ToString()

{

return string.Format("{0, -35:S} {1,4:D} {2, 12:N0}", nom, rang2003, freq2004 );

}

public int CompareTo(object obj) {

return nom.ToUpper().CompareTo( ((Station) obj).nom.ToUpper() ) ;

}

}

(12)

class Interface3 {

static void LireRemplir(string nomFichier, Station[] stat, out int n)

{

n = 0; // compteur du nombre de dtations lues

StreamReader aLire = File.OpenText(nomFichier);

string ligneLue = null;

while ( (ligneLue = aLire.ReadLine()) != null) stat[n++] = new Station(ligneLue);

aLire.Close();

Console.WriteLine("\nOn vient de creer un tableau de "

+ n + " stations");

}

static void Afficher(Station[] stat, int nbStat, int debut, int fin, string message)

{

Console.WriteLine("\nAffichage partiel du tableau des stations " + message);

for (int i = 0; i < nbStat; i++)

if (i < debut || i >= nbStat - fin)

Console.WriteLine("{0,6:D}) {1}", i, stat[i]);

else if (i == debut+1)

Console.WriteLine("etc .... ");

Console.WriteLine();

}

static void Main(string[] args) {

const int MAX_STAT = 70; // au maximum, 70 stations Station[] stat = new Station[MAX_STAT];

int nbStat;

LireRemplir("R:\\metro.txt", stat, out nbStat);

Afficher(stat, nbStat, 7, 4, "avant le tri");

Array.Sort(stat, 0, nbStat);

Afficher(stat, nbStat, 3, 5,

"apres le tri avec Array.Sort");

int indice = Array.BinarySearch(stat, 0, nbStat, new Station("Guy-Concordia", 0, 0));

Console.WriteLine("A l'indice " + indice + ", on trouve :\n" + stat[indice]);

indice = Array.BinarySearch(stat, 0, nbStat, new Station("Laval", 0, 0));

if (indice < 0)

Console.WriteLine("On ne trouve pas Laval");

(13)

} } /* Exécution:

On vient de creer un tableau de 65 stations

Affichage partiel du tableau des stations avant le tri

0) MC-GILL 1 11 333 531 1) BERRI-UQAM 2 11 067 519 2) LONGUEUIL-UNIVERSITE-DE-SHERBROOKE 5 7 375 439 3) GUY-CONCORDIA 4 7 077 669 4) ATWATER 6 6 535 564 5) COTE-VERTU 9 6 387 345 6) PEEL 8 6 273 357 etc ....

61) ASSOMPTION 62 973 051 62) ACADIE 63 936 535 63) GEORGES-VANIER 64 695 482 64) DE LA SAVANE 65 690 673

Affichage partiel du tableau des stations apres le tri avec Array.Sort 0) ACADIE 63 936 535

1) ANGRIGNON 15 4 493 057 2) ASSOMPTION 62 973 051 etc ....

60) UNIVERSITE-DE-MONTREAL 38 2 610 922 61) VENDOME 12 4 889 583 62) VERDUN 51 1 529 707 63) VIAU 34 2 617 979 64) VILLA-MARIA 33 2 753 590

A l'indice 24, on trouve :

GUY-CONCORDIA 4 7 077 669 On ne trouve pas Laval

Press any key to continue

*/

Références

Documents relatifs

Dilemme, dont la seule issue possible est d’installer une méthode evolue() dans la classe Ressource , tout en déclarant cette méthode « abstraite », c’est-à-dire sans

• Ces attributs affectent toutes les cellules de Ces attributs affectent toutes les cellules de la ligne.

On constate qu’une classe abstraite (exemple BufferedReader) contient au moins une méthode abstraite (exemple : abstract void close()). Création d’un fichier

Dans un langage de programmation sans orientée objet (Pascal, C, … ), il est interdit d'utiliser le même nom pour deux sous-programmes différents. Les langages C#, C++, JAVA,

Malgré que les valeurs des deux paramètres a et b ont été bien permutés dans la fonction echanger, on a modifié sur les copies de age1 et age2 et ces modifications ne sont

/* cette méthode permet de déterminer et de retourner le cercle ayant le rayon le plus grand entre le cercle courant et un autre cercle */. public Cercle plusGrand

Dans object, cette méthode compare selon la référence car les auteurs de cette méthode ne savent rien sur les classes créées plus tard pour comparter le contenu de deux objets.

Remarque: une classe abstraite peut posséder des méthodes concrètes ou abstraites; si une classe possède une méthode abstraite, toutes les classes dérivées devront implémenter