Surcharge des opérateurs sdz

    Publicités

Users Who Are Viewing This Thread (Total: 0, Members: 0, Guests: 0)

arnaud39

Membre
Mar 21, 2012
92
0
311
43
Salut a tous! Ce cours du site du zéro est en béta-test, mais j'ai un accé spécial a ces cours. Le voici juste pour vous :noel:


Par minato13
Difficulté : Intermédiaire Durée d'étude : 30 minutes
Bonjour à tous et à toutes !

Vous avez lu le tutoriel officiel du C# du Site du Zéro et vous en voulez encore ? Alors le mini-tuto est parfait pour vous ! Ici nous allons aborder la surcharge des opérateurs, ceci rendra votre code encore plus lisible. Pour faire court, dans ce chapitre je vais vous présenter comment redéfinir le comportement des opérateurs.

Trêve de bavardages allons-y !
Retour en haut
Sommaire du tutoriel :

Introduction
Les opérateurs arithmétiques
Les opérateurs de comparaison
L'opérateur d'indexation et de cast
Q.C.M.
Retour en haut
Introduction

Qu'est ce qu'on va exactement faire ?


La surcharge des opérateurs est un moyen de rendre son code plus lisible en redéfinissant l'implémentation des opérateurs dans une classe. Par exemple, pour additionner deux classes dans les opérateurs redéfinis, nous aurions dû faire ceci :

Code : C# - Sélectionner
1
valeur3 = Addition( valeur1, valeur2);


Voilà ce que vous allez réussir à faire à la fin de ce chapitre :

Code : C# - Sélectionner
1
valeur3 = valeur1 + valeur2;


Il faut avouer que c'est plus facile de lire le deuxième exemple que le premier.

Notre premier exemple :

Pour ce chapitre, nous utiliseron cet exemple, une classe Taille qui va stocker une taille en mètres et en centimètres. Le constructeur acceptera des paramètres par défaut ou un autre objet de type Taille. Et si les centimètres dépassent de 100, vous convertissez ceci en mètres pour avoir une taille cohérente. Je n'ai pas envie d'avoir 1 mètre 120 centimètres ! Sa méthode ToString() sera également redéfini. Afin de vous mettre dans le bain, vous allez implémenter cette classe, allez ! Zou !

Secret (cliquez pour afficher)


Instancions maintenant quelques objets pour voir si tout ceci marche :
Code : C# - Program.cs - Sélectionner
1
2
3
4
5
6
static void Main(string[] args) {
Taille t1 = new Taille(), t2 = new Taille(2, 50), t3 = new Taille(1, 250);
Console.WriteLine(t1);
Console.WriteLine(t2);
Console.WriteLine(t3);
}


Résultat :
Code : Console - Sélectionner
0m0cm
2m50cm
3m50cm
Appuyez sur une touche pour continuer...


C'est bon pour les préparatifs ! Maintenant on peut attaquer la surcharge des opérateurs !
Retour en haut
Les opérateurs arithmétiques

Commençons par le plus facile, c'est-à-dire les opérateurs arithmétiques, soit +, -, *, / et %.
La signature de la méthode est la suivante :

Code : C# - Sélectionner
1
public static Objet operator[+ - * / %](Objet a, Objet b)


Plusieurs points :
Même si je dit que nous redéfinissons le comportement des opérateurs, nous n'utilisons pas override, tout simplement que les classes n'ont forcément pas besoin d'opérateurs à redéfinir.
La méthode est déclarée static, faites-y attention !
Les opérateurs à redéfinir sont placées entre les crochets après le operator.
La méthode va renvoyer un objet, qui sera stocké dans le résultat ( Ou nulle part dans la mémoire de l'ordinateur ).


Implémentons l'opérateur + !


Nous allons y aller ensemble, comme c'est notre premier opérateur à redéfinir, pour cela, nous allons construire le corps de la méthode :
Code : C# - Sélectionner
1
2
3
public static Taille operator +(Taille a, Taille b) {

}


Qu'avons-nous à implémenter dedans ?
Nous allons créer un objet de type Taille qui s'appellera c qui ne contiendra rien. Nous allons ajouter dans cet objet les mètres de a et ceux de b dans les mètres de c. Après nous ferons pareil pour les centimètres. Etant donné que la conversion se fait automatiquement ( En tout cas dans ma classe ), nous sommes tranquilles !

Bref :
Code : C# - Sélectionner
1
2
3
4
5
6
public static Taille operator +(Taille a, Taille b) {
Taille c = new Taille();
c.centimetres = a.centimetres + b.centimetres;
c.metres = a.metres + b.metres;
return c;
}


Vous n'avez pas remarqués une erreur dans ce bout de code et qui est pourtant bon ?
Les attributs des Objets en paramètres, on ne peut pas y accéder normalement, eh bien je vous révèle ceci, comme nous sommes dans la même classe, nous pouvons autoriser cette chose !

#Bonus Track :


La surcharge des opérateurs, c'est vraiment un bon titre, car on retrouve le terme surcharge. Autrement dit, nous pouvons redéfinir l'opérateur + par exemple plusieurs fois !

Il suffira juste de changer les types des paramètres, exemple :
Code : C# - Sélectionner
1
2
3
4
5
public static Taille operator +(Taille a, int _metres) {
Taille t = new Taille();
t.metres += _metres;
return t;
}


Alors ? Pas mal hein ?

Exercice :

Implémentez l'opérateur - où nous pourrions soustraire des mètres, soit un autre objet de type Taille, attention ! Je ne veux pas une taille négative !

Le cas des opérateurs raccourcis :


Eh ! Ça existe ça :
Code : C# - Sélectionner
1
public static Taille operator +=(Taille a){/*...*/}
??


C'est justement de quoi je voulais parler, le C# va, sur ce coup-là, être très sympa !
En fait il va combiner l'opérateur = et l'opérateur +. Voilà pour cette anecdote.

Pour compléter ceci, les opérateurs de ce style ne sont pas surchargeables, eh oui ! Tout les opérateurs ne sont surchargeables ! Pour en avoir la liste, consultez la page du MSDN.
Retour en haut
Les opérateurs de comparaison

Les opérateurs de comparaison :

Ces opérateurs sont ceux-ci :
<
>
==
!=
<=
>=

La signature de la méthode :

La signature de la méthode est pareil à celle des opérateurs arithmétiques, à un poil près !
Code : C# - Sélectionner
1
public static bool operator[ < > <= >= == !=](Objet a, Objet b)


Cette méthode renvoi bien sûr un bool pour indiquer le résultat de la comparaison. Les opérateurs sont entre les crochets, et pour finir, les types des paramètres peuvent êtres différents !

Des opérateurs paires :


Les opérateurs de comparaison possèdent une particularité, ils doivent êtres paires ! Exemple, si un objet est plus petit qu'un autre, l'autre est sûrement plus grand que le premier.
Donc, ces opérateurs paires sont :
< et >
== et !=
<= et >=

Nous allons implémentez l'opérateur < ainsi que l'opérateur >.

Ne confondez pas ceci avec les opérateurs contraires ! Exemple, l'opérateur contraire de < est >=, pas > !! Pourquoi me direz-vous ? Tout bonnement que si A n'est pas inférieur ( < ) à B, c'est qu'il est soit pareil, soit supérieur ! ( >= )


Implémentons !


C'est parti !

Code : C# - Sélectionner
1
2
3
4
5
6
7
8
public static bool operator <(Taille a, Taille b) {
if((a.metres < b.metres) || ( a.metres == b.metres && a.centimetres < b.centimetres))
return true;
return false;
}
public static bool operator >(Taille a, Taille b) {
return b < a;
}


Aussi, comme nous implémentons un opérateur, autant l'utiliser pour implémenter l'autre !

Exercices !

Implémentez :

Les opérateurs == et !=.
Ainsi que <= et >=.
Bonne chance !
Retour en haut
L'opérateur d'indexation et de cast

L'opérateur d'indexation :


L'opérateur d'indexation [] est utile dans les tableaux ou les listes... Bref, tout objet qui contient plusieurs valeurs et où l'on peut accéder aux valeurs grâce à des clés. Ceci peut être un nombre ou une chaîne de caractères.

Bref, nous allons implémentez cet opérateur !

Eh ! J'ai regardé le MSDN et il n'est pas surchargeable !


En vl'à un qui n'est pas tombé dans le panneau ! C'est vrai, cet opérateur n'est pas surchargeable, mais alors... Comment on fait ?

Dans ce cas nous allons utiliser un indexeur, et celui-là pourra accepter n'importe quel paramètre ! Ceci s'utilise comme une propriété, avec un get et un set. Et nous mettrons this en nom pour montrer que c'est l'objet lui-même que nous utilisons.

Voilà un exemple :

Code : C# - Sélectionner
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public class Liste<T> {

public List<T> list;
public List<T> List {
get { return list; }
}

public T this[int indice]{
get { return list[indice]; }
set { list[indice] = value; }
}

public Liste() {
list = new List<T>();
}
}


Ce qui se trouve entre les crochets peut être un String, un double, etc...
C'est bien les indexeurs !

L'opérateur de cast :


Bon cette fois...

Il n'est pas surchargeable !

On m'a pris de vitesse, bon, ça m'économise des lignes, alors autant aller au but. Pour redéfinir le cast d'un objet, c'est comme l'opérateur d'indexation, c'est illimité !!

Cependant, il existe deux types de casts :

Le cast dit implicite, c'est-à-dire que nous ne sommes pas obligés de préciser à C# entre des parenthèses avec le type dedans en quel type caster.
Le cast dit explicite, nous somme obligés d'indiquer à C# avec les parenthèses et le type dedans en quel type caster l'objet.


Ces casts sont différents, car le cast explicite provoque une perte de données, alors que le cast implicite garde les données, mais sous une autre forme.

Le cast implicite avec implicit :


Voilà notre exemple de classe :

Code : C# - Sélectionner
1
2
3
4
5
6
7
8
9
10
11
public class Caracter {

private char carac;
public char Carac {
get { return carac; }
set { carac = value; }
}

public Caracter(char letter) { carac = letter; }

}


Et la signature d'une telle méthode :

Code : C# - Sélectionner
1
public static implicit operator type_du_resultat(type_a_caster objet_a_caster)


Vous connaissez maintenant, allez ! Il faut pouvoir caster un Caracter en int et inversement. Vous verrez que c'est très facile.

Code : C# - Sélectionner
1
2
3
4
5
6
public static implicit operator Caracter(int objetACaster) {
return new Caracter((char)objetACaster);
}
public static implicit operator int(Caracter objetACaster) {
return (int)objetACaster.carac;
}


Et dans le Main :

Code : C# - Sélectionner
1
2
3
4
5
6
public static void Main(String[] args){
Caracter c = new Caracter('a');
int i = c;
int i2 = 34;
Caracter c2 = i2;
}


Le cast explicite avec explicit :


Comme je l'ai dit plus haut, le cast explicite, fait perdre des données, alors que le cast implicite garde les données intactes. Vous avez fait plusieurs fois ce genre de cast, par exemple une classe A et une classe B héritant de A, dans ce cas, nous pouvions faire ceci :
Code : C# - Sélectionner
1
2
B b = B();
A a = (A)b;


La variable a va seulement récupérer les méthodes et attributs qui héritaient de la classe-mère. Et le reste ? Ce qui est propre à la classe B ? Il a été perdu. La variable a a repris que ce qui lui servait.

Voilà pour l'anecdote, maintenant, voyons comment effectuer cela !
Privilégiez le cast implicite au cast explicite, sinon vous allez perdre vos données et ceci peut fausser l'utilisateur de votre classe.


Nous allons prendre cette classe :

Code : C# - Personnage.cs - Sélectionner
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public class Personnage {

public string nom;
public string prenom;
public int age;
public string adresse;
public string nomDuChien;

public Personnage(int age, string nom, string prenom, string adresse, string nameDog = "Médor") {
this.age = age;
this.nom = nom;
this.prenom = prenom;
this.adresse = adresse;
this.nomDuChien = nameDog;
}


}


J'ai enlevé les mécanismes de l'encapsulation afin d'alléger le code.
Nous allons maintenant créer une autre classe :
Code : C# - Sélectionner
1
2
3
4
5
6
7
8
9
10
11
12
public class Info {
public string nom, prenom, adresse;
public int age;

public Info(string nom,string prenom,string adress,int age){
this.nom = nom;
this.prenom = prenom;
this.age = age;
this.adresse = adress;
}

}


Grâce au cast explicite, nous allons pouvoir caster un objet Info en Personnage et inversement, c'est parti !

Voilà pour la classe Personnage, cherchez maintenant pour Info :
Code : C# - Sélectionner
1
2
3
public static explicit operator Info(Personnage p) {
return new Info(p.nom, p.prenom, p.adresse, p.age);
}//Ceci est à mettre dans la classe Personnage


Secret (cliquez pour afficher)


Vous verrez dans le Main que ceci marche :
Code : C# - Sélectionner
1
2
3
4
5
6
7
static void Main(string[] args) {
Personnage p = new Personnage(13, "Albert", "Einstein", "Adresse inconnu", "Cookie");
Info i = (Info)p;

Info i2 = new Info("Minato", "Namikaze", "Konoha", 20);
Personnage p2 = (Personnage)i2;
}


Voilà !