Top Banner
Programmation par objets en C++ Jean-Christophe Engel IFSIC - Université Rennes 1
105

Jean-Christophe Engel IFSIC - Université Rennes 1...IFSIC – Université Rennes 1 Programmation par objets en C++ Classes Implémentation rationnel.cc importer la définition de

Sep 02, 2020

Download

Documents

dariahiddleston
Welcome message from author
This document is posted to help you gain knowledge. Please leave a comment to let me know what you think about it! Share it to your friends and learn new things together.
Transcript
Page 1: Jean-Christophe Engel IFSIC - Université Rennes 1...IFSIC – Université Rennes 1 Programmation par objets en C++ Classes Implémentation rationnel.cc importer la définition de

Programmation par objets en C++

Jean-Christophe Engel

IFSIC - Université Rennes 1

Page 2: Jean-Christophe Engel IFSIC - Université Rennes 1...IFSIC – Université Rennes 1 Programmation par objets en C++ Classes Implémentation rationnel.cc importer la définition de

IFSIC – Université Rennes 1 Programmation par objets en C++

Programmation par objets en C++

1. Éléments de base .....................................................................................................3

2. Classes ....................................................................................................................11

3. Pointeurs .................................................................................................................20

4. Allocation dynamique .............................................................................................27

5. Références ..............................................................................................................33

6. Héritage ..................................................................................................................39

7. Surcharge des opérateurs .......................................................................................57

8. Exceptions ..............................................................................................................72

9. Généricité - Modèles ...............................................................................................76

10. Bibliothèque standard ...........................................................................................80

11. Bibliographie .......................................................................................................105

Jean-Christophe Engel 2 janvier 2007

Page 3: Jean-Christophe Engel IFSIC - Université Rennes 1...IFSIC – Université Rennes 1 Programmation par objets en C++ Classes Implémentation rationnel.cc importer la définition de

IFSIC – Université Rennes 1 Programmation par objets en C++

Éléments de base

Types prédéfinis

● logique : bool termine = false, correct(true);

● caractère : char lettre('é'), question = '?';

● entier : const int nbElements(423);

● réel : float diam = -3.14159;

● réel double : double tresprecis(0.12345678987654321);

● chaîne : string message("Programmation objet en C++");

● tableaux : int nombres[50]; nombres[i] = -2; // i ∈ { 0 .. 49 }

Opérateurs

● affectation : =

● arithmétiques : + - * / % ++ -- +=

● relationnels : == != < > <= >=

● logiques : && || !

● chaînes : + ==

Jean-Christophe Engel 3 janvier 2007

Page 4: Jean-Christophe Engel IFSIC - Université Rennes 1...IFSIC – Université Rennes 1 Programmation par objets en C++ Classes Implémentation rationnel.cc importer la définition de

IFSIC – Université Rennes 1 Programmation par objets en C++

Structures de contrôle

● commentaire /* multiligne */ // fin de ligne

● bloc { déclarations ... instructions }

● conditionnelle if (condition) blocVrai else blocFaux

● itération while (condition) blocItération

● itération for (expInit ; condition ; expSuite) blocItération

● choix multiple switch (expression) {case v1 : instructions; break; case v2 : instructions; break; ...default : instructions; break; }

entrées/sorties opérateurs << et >>

#include <iostream>using namespace std;cout << expression1 << expression2 << ... << endl;cin >> variable1 >> variable2 >> ... ;

Jean-Christophe Engel 4 janvier 2007

Page 5: Jean-Christophe Engel IFSIC - Université Rennes 1...IFSIC – Université Rennes 1 Programmation par objets en C++ Classes Implémentation rationnel.cc importer la définition de

IFSIC – Université Rennes 1 Programmation par objets en C++

Fonctions

définition static T identificateur(T1 param1, ..., Tn Paramn) blocCorps

static int maxNombres(int a, int b) { int max;if (a > b) { max = a; } else { max = b; }return max;

}

prototype static T identificateur(T1 param1, ..., Tn Paramn);

static int maxNombres(int a, int b);

appelint x, y, z ; x = maxNombres(y, z);

paramètresparamètres par valeur : paramètre formel = copie du paramètre effectifrésultat par valeur

Jean-Christophe Engel 5 janvier 2007

Page 6: Jean-Christophe Engel IFSIC - Université Rennes 1...IFSIC – Université Rennes 1 Programmation par objets en C++ Classes Implémentation rationnel.cc importer la définition de

IFSIC – Université Rennes 1 Programmation par objets en C++

Fonctions

paramètres par défaut

static int incrementer(int init = 0, int increment = 1) { return init + increment; }...int nb = incrementer(); // nb : 1nb = incrementer(nb); // nb : 2nb = incrementer(nb, 5); // nb : 7

surcharge

fonctions de même noms différenciées par le nombre et le type des paramètresstatic float maxNombres(float x, float y);static float maxNombres(float x, float y, float z);static Rationnel maxNombres(Rationnel r, Rationnel s);

Jean-Christophe Engel 6 janvier 2007

Page 7: Jean-Christophe Engel IFSIC - Université Rennes 1...IFSIC – Université Rennes 1 Programmation par objets en C++ Classes Implémentation rationnel.cc importer la définition de

IFSIC – Université Rennes 1 Programmation par objets en C++

Fonctions

tableau en paramètre

– tableaux passés par variable : paramètre formel = paramètre effectif

– paramètre effectif : identificateur du tableau

– pas de tableau en résultat de fonction

static void saisirTableau(float tnb[ ], int nb) {for (int i = 0; i < nb ; ++i) { cin >> tnb[i]; }

}

static float sommeTableau(const float tnb[ ], int nb) {float somme(0);for (int i = 0; i < nb ; ++i) { somme += tnb[i]; }return somme;

}

...float nombres[100];saisirTableau(nombres, 50);float somme = sommeTableau(nombres, 50);

Jean-Christophe Engel 7 janvier 2007

Page 8: Jean-Christophe Engel IFSIC - Université Rennes 1...IFSIC – Université Rennes 1 Programmation par objets en C++ Classes Implémentation rationnel.cc importer la définition de

IFSIC – Université Rennes 1 Programmation par objets en C++

#include <iostream>using namespace std;

// Prototypes des fonctions

static int lireTableau ( int tnb[ ], int nmax);static int lireNombre (void);static float calculerMoyenne (const int tnb[ ], int compteur);static void afficherValeurs (const int tnb[ ], int compteur);

// Calculer la moyenne d'une suite d'entiers positifs

int main(void){ const int NB = 10; // nombre maxi d'éléments int valeurs[NB] ; // tableau des valeurs

// saisir les éléments du tableau int compteur = lireTableau(valeurs, NB); // rend le nombre de valeurs lues if (compteur > 0) { float moyenne = calculerMoyenne(valeurs, compteur); // Calculer la moyenne afficherValeurs(valeurs, compteur); // afficher les valeurs lues cout << "Moyenne = " << moyenne << endl; // afficher la moyenne } return 0;}

Jean-Christophe Engel 8 janvier 2007

Page 9: Jean-Christophe Engel IFSIC - Université Rennes 1...IFSIC – Université Rennes 1 Programmation par objets en C++ Classes Implémentation rationnel.cc importer la définition de

IFSIC – Université Rennes 1 Programmation par objets en C++

/* Lire une suite d'entiers positifs et les mettre dans un tableau Paramètres donnés : int nmax : nombre max de valeurs à lire Paramètres modifiés : int tnb[]: tableau des valeurs Résultat : nombre de valeurs lues ... */

static int lireTableau(int tnb[ ], int nmax) { int nombrelu, compteur = 0;

cout << "Tapez une suite d'entiers > 0, terminée par 0\n"; nombrelu = lireNombre(); // Lire un nombre >= 0 while (nombrelu != 0 && compteur < nmax) { // fin si 0 ou plus de place

tnb[compteur] = nombrelu;compteur = compteur + 1;nombrelu = lireNombre(); // Lire un nombre >= 0

} return compteur;}// Lire un nombre; s'assurer qu'il est >= 0 et le renvoyerstatic int lireNombre(void) { int unnombre; cin >> unnombre; while (unnombre < 0) { cout << "Hé! On vous a dit un nombre entier positif ou nul\n"; cin >> unnombre; } return unnombre; // unnombre >= 0}

Jean-Christophe Engel 9 janvier 2007

Page 10: Jean-Christophe Engel IFSIC - Université Rennes 1...IFSIC – Université Rennes 1 Programmation par objets en C++ Classes Implémentation rationnel.cc importer la définition de

IFSIC – Université Rennes 1 Programmation par objets en C++

// Calculer la moyenne// pré-condition : au moins un élément dans le tableau (compteur > 0)static float calculerMoyenne(const int tnb[ ], int compteur){ int somme = 0; for (int i = 0; i < compteur; ++i) {

somme = somme + tnb[i]; }

float moyenne = (float) somme / (float) compteur; return moyenne;}

// Afficher les valeurs luesstatic void afficherValeurs(const int tnb[ ], int compteur){ for (int i = 0; i < compteur; ++i) { cout << tnb[i] << " "; } cout << endl;}

Jean-Christophe Engel 10 janvier 2007

Page 11: Jean-Christophe Engel IFSIC - Université Rennes 1...IFSIC – Université Rennes 1 Programmation par objets en C++ Classes Implémentation rationnel.cc importer la définition de

IFSIC – Université Rennes 1 Programmation par objets en C++

Classes

Abstraction

définir une entité par ses propriétés et les services qu'elle peut offrir, indépendamment de leur représentation et de l'utilisation qu'on peut en faire

☛ interface = spécification de l'abstraction d'une entité

Encapsulation de la représentation

● définir une représentation (cachée) des données internes

● programmer les services de l'interface

☛ mise en oeuvre (implémentation)

Avantages

● meilleure fiabilité du logiciel

● localise l'effet des erreurs

● autorise le concepteur à modifier la mise en oeuvre

Jean-Christophe Engel 11 janvier 2007

Page 12: Jean-Christophe Engel IFSIC - Université Rennes 1...IFSIC – Université Rennes 1 Programmation par objets en C++ Classes Implémentation rationnel.cc importer la définition de

IFSIC – Université Rennes 1 Programmation par objets en C++

Classes

Rationnel : spécification (informelle)

But : représenter et manipuler des fractions rationnelles

opérations :

● créer et initialiser une fraction rationnelle ; postcondition : la fraction construite doit être valide, irréductible et avoir

un dénominateur strictement positif

● afficher une fraction rationnelle

● comparer deux fractions rationnelles (inégalité)

● calculer la somme de deux fractions rationnelles

● calculer l'inverse d'une fraction rationnelle

● calculer la valeur d'une fraction rationnelle

● calculer le max de deux fractions rationnelles

...

Jean-Christophe Engel 12 janvier 2007

Page 13: Jean-Christophe Engel IFSIC - Université Rennes 1...IFSIC – Université Rennes 1 Programmation par objets en C++ Classes Implémentation rationnel.cc importer la définition de

IFSIC – Université Rennes 1 Programmation par objets en C++

Classes

Déclaration rationnel.h

class Rationnel {public : // interface Rationnel(int num = 0, int den = 1); // constructeur

// méthodes bool estInferieur(Rationnel r) const; void afficher(void) const; Rationnel somme(Rationnel r) const; Rationnel inverse(void) const; float getValeur (void) const;

static Rationnel max(Rationnel r1, Rationnel r2); // méthode de classe

// implémentation partielle (représentation)private: void normaliser(void); // méthode privée int numerateur, denominateur; // attributs privés};

Jean-Christophe Engel 13 janvier 2007

Page 14: Jean-Christophe Engel IFSIC - Université Rennes 1...IFSIC – Université Rennes 1 Programmation par objets en C++ Classes Implémentation rationnel.cc importer la définition de

IFSIC – Université Rennes 1 Programmation par objets en C++

Classes

Accessibilité

publique (public) : attribut ou méthode accessible à toute fonction ou méthode

privée (private) : attribut ou méthode accessible aux méthodes de la classe

protégée (protected) : attribut ou méthode accessible aux méthodes - de la classe- des classes dérivées

Autres caractéristiques

● attribut ou méthode de classe : static ...

● constante de classe : static const ...

● méthode qui ne modifie pas l'instance courante : ... const

Jean-Christophe Engel 14 janvier 2007

Page 15: Jean-Christophe Engel IFSIC - Université Rennes 1...IFSIC – Université Rennes 1 Programmation par objets en C++ Classes Implémentation rationnel.cc importer la définition de

IFSIC – Université Rennes 1 Programmation par objets en C++

Classes

Implémentation rationnel.cc

● importer la définition de la classe #include "rationnel.h"

● accès attributs de l'instance courantevoid Rationnel::afficher(void) const{ cout << numerateur; if (denominateur != 1) { cout << "/" << denominateur; }}

● accès attributs d'une autre instance : opérateur •bool Rationnel::estInferieur(Rationnel r) const{ return numerateur * r•denominateur < r•numerateur * denominateur;}

Jean-Christophe Engel 15 janvier 2007

Page 16: Jean-Christophe Engel IFSIC - Université Rennes 1...IFSIC – Université Rennes 1 Programmation par objets en C++ Classes Implémentation rationnel.cc importer la définition de

IFSIC – Université Rennes 1 Programmation par objets en C++

Classes

● constructeur

– méthode de même nom que la classe, pas de type résultat

– appelé automatiquement après que l'instance a été construite :

par déclaration ou par allocation dynamique

– sert à initialiser les attributs d'une instance qui vient d'être construite

syntaxe "classique" dans le corps du constructeur

liste d'initialisation ; seule possibilité pour un attribut :

constant

d'un type classe

référence

– si absent, appel d'un constructeur sans paramètre par défaut

● exempleRationnel::Rationnel(int num, int den) : numerateur(num), denominateur(den){ normaliser();}

Jean-Christophe Engel 16 janvier 2007

Page 17: Jean-Christophe Engel IFSIC - Université Rennes 1...IFSIC – Université Rennes 1 Programmation par objets en C++ Classes Implémentation rationnel.cc importer la définition de

IFSIC – Université Rennes 1 Programmation par objets en C++

Classes

● création d'instance par déclarationRationnel r1(-3,4); // -3/4Rationnel r2(5); // 5/1Rationnel r3; // 0/1Rationnel trat[500]; // appel du constructeur sans paramètre de Rationnel

// pour initialiser chaque élément du tableau

● appel de méthoder1.afficher();

if (r1.estInferieur(r2)) { ... }

● méthode de classe (static)

☛ ne s'applique pas sur une instance

Rationnel Rationnel::max(Rationnel r1, Rationnel r2){ if (r1.estInferieur(r2)) { return r2; } else { return r1; }}

appel : r3 = Rationnel::max(r1, r2);

Jean-Christophe Engel 17 janvier 2007

Page 18: Jean-Christophe Engel IFSIC - Université Rennes 1...IFSIC – Université Rennes 1 Programmation par objets en C++ Classes Implémentation rationnel.cc importer la définition de

IFSIC – Université Rennes 1 Programmation par objets en C++

Classes

● destructeur

– méthode de nom ~classe, sans paramètre ni type résultat

– appelé juste avant la destruction de l'instance

– sert à dé-initialiser l'instance et non à la détruire

– pour une instance créée par déclaration, l'appel du destructeur est implicite quand l'instance arrive en "fin de vie" : sortie de sa portée, fin du programme

– pour une instance créée dynamiquement (avec new), l'appel du destructeur doit être fait explicitement (par l'opérateur delete et pas avec le nom ~classe)

– sert principalement à libérer la mémoire (ou d'autres ressources externes à l'instance) allouée (dynamiquement) par le constructeur.

Rationnel::~Rationnel(void){

cout << "Le rationnel "; afficher() ;cout << " est sur le point d'être détruit\n";

}

Jean-Christophe Engel 18 janvier 2007

Page 19: Jean-Christophe Engel IFSIC - Université Rennes 1...IFSIC – Université Rennes 1 Programmation par objets en C++ Classes Implémentation rationnel.cc importer la définition de

IFSIC – Université Rennes 1 Programmation par objets en C++

Types construits

énumérations

enum Mois { janvier, fevrier, mars, avril, mai, juin, juillet, aout, septembre, octobre, novembre, decembre };

structures

● déclarateur struct

● attributs et méthodes publics par défautstruct Date {

int jour; Mois mois; int annee; Date(int j, Mois m, int a) : jour(j), mois(m), annee(a) {};

};Date aujourdhui(10, avril, 2002);aujourdhui.mois = mai;

types synonymes

typedef int Position;

Position p; // ⇔ int p;

typedef Rationnel * PtrRationnel;

PtrRationnel pr; // ⇔ Rationnel * pr;

Jean-Christophe Engel 19 janvier 2007

Page 20: Jean-Christophe Engel IFSIC - Université Rennes 1...IFSIC – Université Rennes 1 Programmation par objets en C++ Classes Implémentation rationnel.cc importer la définition de

IFSIC – Université Rennes 1 Programmation par objets en C++

Pointeurs

définition

variable dont la valeur est l'adresse d'une variable ; un pointeur pointe sur une variable d'un type précis, indiqué dans la déclaration du pointeur.

déclaration : T * p;

int * pi;float * pr1, * pr2;Date * pd; Rationnel * pr;

Dans la déclaration T * p; le type du pointeur est : T *

initialisation : opérateur &

int i (123); int * pi = & i; Date d1(1, mai, 2000); Date * pd(& d1);Rationnel r1(5, -2); Rationnel * pr = & r1;

Jean-Christophe Engel 20 janvier 2007

-5

2

123

pd

pr

pi

2000

mai

1

Page 21: Jean-Christophe Engel IFSIC - Université Rennes 1...IFSIC – Université Rennes 1 Programmation par objets en C++ Classes Implémentation rationnel.cc importer la définition de

IFSIC – Université Rennes 1 Programmation par objets en C++

Pointeurs

indirection : opérateurs * et →

* p : variable désignée par le pointeur

si p est déclaré ainsi : T * p; alors * p est du type T

* pi : int, valeur de i

* pd : Date, valeur de d1

* pr : Rationnel, valeur de r1

● On peut donc appliquer sur l'expression * p les opérations du type correspondant*pi += 1;(*pd)•annee = 2004;(*pr)• afficher();

● Cas des structures et classes : (*p)• attribut ⇔ p → attribut (idem méthodes)pd → annee = 2004; pr → afficher();

Jean-Christophe Engel 21 janvier 2007

Page 22: Jean-Christophe Engel IFSIC - Université Rennes 1...IFSIC – Université Rennes 1 Programmation par objets en C++ Classes Implémentation rationnel.cc importer la définition de

IFSIC – Université Rennes 1 Programmation par objets en C++

Pointeurs

passage de paramètre par pointeur

● paramètre à modifier :

– paramètre effectif est l'adresse de la variable à modifier

– paramètre formel est un pointeur, initialisé à l'appel par l'adresse (valeur du paramètre effectif) : il désigne la variable à modifier

fonction appelante

float r1, r2;...permuter(& r1, & r2); // ou bienfloat * pr1(& r1), * pr2(& r2);permuter(pr1, pr2);

fonction appelée

void permuter(float * p1, float * p2){ float x; x = *p1; *p1 = *p2; *p2 = x;}

Jean-Christophe Engel 22 janvier 2007

pr2 r2

r1pr1 p1

p2

Page 23: Jean-Christophe Engel IFSIC - Université Rennes 1...IFSIC – Université Rennes 1 Programmation par objets en C++ Classes Implémentation rationnel.cc importer la définition de

IFSIC – Université Rennes 1 Programmation par objets en C++

Pointeurs

passage de paramètre par pointeur

● efficacité : gain de place et de temps

– rendre non modifiable la variable désignée par le pointeur : const

– rendre non modifiable le pointeur lui-même : constbool Rationnel::estInferieur(const Rationnel * const pr) const{ return numerateur * pr → denominateur < denominateur * pr → numerateur;}

Jean-Christophe Engel 23 janvier 2007

Page 24: Jean-Christophe Engel IFSIC - Université Rennes 1...IFSIC – Université Rennes 1 Programmation par objets en C++ Classes Implémentation rationnel.cc importer la définition de

IFSIC – Université Rennes 1 Programmation par objets en C++

Pointeurs

fonction qui renvoie un pointeur

le pointeur renvoyé ne doit pas désigner une variable locale; il doit désigner soit une variable dont l'adresse est paramètre de la fonction, soit une variable

allouée dynamiquement.

float * pmax;

pmax = pointeurMax(& r1, & r2);// ou bienpmax = pointeurMax(pr1, pr2);

float * pointeurMax(float * p1 , float * p2){ float * pmax;

if (*p1 > *p2) { pmax = p1; } else { pmax = p2; } return pmax;}

Jean-Christophe Engel 24 janvier 2007

Page 25: Jean-Christophe Engel IFSIC - Université Rennes 1...IFSIC – Université Rennes 1 Programmation par objets en C++ Classes Implémentation rationnel.cc importer la définition de

IFSIC – Université Rennes 1 Programmation par objets en C++

Pointeurs

Pointeurs et tableaux

● initialisation float v[NB], * pv = &v[0];

● relation 1 *(pv + i) = v[i]

● relation 2 v ≡ & v[0]v + i ≡ & v[i]

● relation 3 v[i] ≡ *(v + i) ≡ *(pv + i) ≡ pv[i]

float somme = 0;for (int i = 0; i < compteur; ++i) {

somme = somme + v[i];}// ou bienfor (int i = 0; i < compteur; ++i) {

somme = somme + pv[i];}

// ou bienfor (int i = 0; i < compteur; ++i) {

somme = somme + *(v + i);}// ou bienfor (int i = 0; i < compteur; ++i) {

somme = somme + *(pv + i);}

Jean-Christophe Engel 25 janvier 2007

0 1 i n-1pv

pv+1

pv+i

pv

Page 26: Jean-Christophe Engel IFSIC - Université Rennes 1...IFSIC – Université Rennes 1 Programmation par objets en C++ Classes Implémentation rationnel.cc importer la définition de

IFSIC – Université Rennes 1 Programmation par objets en C++

Pointeurs

Pointeurs et tableaux

un pointeur n'est pas un tableau

pointeur tableauT * p;

crée un pointeur non initialisé; réserve de la mémoire pour un pointeur : type T *

T v[N];

réserve de la mémoire pour N élts de type T

p = & v[0];

p doit obligatoirement désigner un tableau, créé par déclaration ou par allocation dynamiquep = p + 1;

p désigne l'élément suivant du tableau; si on désire éviter de modifier p par inadvertance, le déclarer avec const : T * const p = &v[0];

v = v + 1;

impossible : v est constant

Jean-Christophe Engel 26 janvier 2007

Page 27: Jean-Christophe Engel IFSIC - Université Rennes 1...IFSIC – Université Rennes 1 Programmation par objets en C++ Classes Implémentation rationnel.cc importer la définition de

IFSIC – Université Rennes 1 Programmation par objets en C++

Allocation dynamique

Objectif : gérer des structures de données de taille variable

Règle : Pas de récupération automatique de la mémoire ; tout instance créée dynamiquement doit être désallouée ...

création : opérateur new

T * p; p = new T(paramètres d'initialisation);

– crée une instance de type T,

– appelle le constructeur adéquat

– renvoie l'adresse de l'instance créée;

● si on ne souhaite pas modifier la valeur de p, on peut le déclarer const, auquel cas l'initialisation doit être faite obligatoirement dans la déclaration :

T * const p = new T(paramètres d'initialisation);

Jean-Christophe Engel 27 janvier 2007

Page 28: Jean-Christophe Engel IFSIC - Université Rennes 1...IFSIC – Université Rennes 1 Programmation par objets en C++ Classes Implémentation rationnel.cc importer la définition de

IFSIC – Université Rennes 1 Programmation par objets en C++

Allocation dynamique

destruction : opérateur delete

delete p;

appelle le destructeur de la classe T (méthode ~T) pour "nettoyer" l'instance pointée par p puis la détruit .

Rationnel * pr = new Rationnel(1, 2); // crée un rationnel...delete pr; // le détruit

cas d'un tableau :

T * const pt = new T[n]; appelle le constructeur sans paramètre de la classe Tpour

chaque élément du tableau

delete [ ] pt; appelle le destructeur pour chaque élément

delete pt; appelle le destructeur uniquement pour le premier élément

Jean-Christophe Engel 28 janvier 2007

Page 29: Jean-Christophe Engel IFSIC - Université Rennes 1...IFSIC – Université Rennes 1 Programmation par objets en C++ Classes Implémentation rationnel.cc importer la définition de

IFSIC – Université Rennes 1 Programmation par objets en C++

Allocation dynamique

allocation dynamique dans une fonction

● fonctionRationnel * Rationnel::somme(Rationnel r) const{ Rationnel * pr = new Rationnel(numerateur * r.denominateur +

r.numerateur * denominateur,denominateur * r.denominateur);

return pr;}

● appelRationnel r1(1, 2), r2(3, 4);Rationnel * pr3 = r1.somme(r2);

Jean-Christophe Engel 29 janvier 2007

pr3 pr

Page 30: Jean-Christophe Engel IFSIC - Université Rennes 1...IFSIC – Université Rennes 1 Programmation par objets en C++ Classes Implémentation rationnel.cc importer la définition de

IFSIC – Université Rennes 1 Programmation par objets en C++

Allocation dynamique

allocation dynamique dans une fonction

Rationnel Rationnel::somme(Rationnel r) const{ Rationnel * pr = new Rationnel(numerateur * r.denominateur +

r.numerateur * denominateur,denominateur * r.denominateur);

return * pr;}

Rationnel r4 = r1.somme(r2);

Jean-Christophe Engel 30 janvier 2007

la variable créée n'est plus accessible

Règle : ne jamais renvoyer une copie d'une variable créée dynamiquement, toujours son adresse.

r4pr

Page 31: Jean-Christophe Engel IFSIC - Université Rennes 1...IFSIC – Université Rennes 1 Programmation par objets en C++ Classes Implémentation rationnel.cc importer la définition de

IFSIC – Université Rennes 1 Programmation par objets en C++

Allocation dynamique

allocation dynamique et destructeur

class TableDeCorrespondance{public: TableDeCorrespondance (int n = 10); // constructeur ~TableDeCorrespondance(void); // destructeur

... // autres méthodes publiques

private: // attributs privés Couple * tc; // pointe sur le premier élt du tableau qui sera créé int taille; // taille du tableau lors de la création int nb; // nombre d'éléments utilisés dans le tableau};

Jean-Christophe Engel 31 janvier 2007

tnb

nb

taille

tc

Page 32: Jean-Christophe Engel IFSIC - Université Rennes 1...IFSIC – Université Rennes 1 Programmation par objets en C++ Classes Implémentation rationnel.cc importer la définition de

IFSIC – Université Rennes 1 Programmation par objets en C++

Allocation dynamique

// constructeurTableDeCorrespondance::TableDeCorrespondance(int n) : tc(new Couple[n]),// créer un tableau de n éléments taille(n), nb(0){ }

// destructeurTableDeCorrespondance::~TableDeCorrespondance(void){ delete [ ] tc; // détruire le tableau alloué dans le constructeur}// utilisation

int main(void) { // crée une table de 5 élts TableDeCorrespondance tnb(5); // etc...}// fin du programme : appel implicite du destructeur de tnb

// ou aussi

int main(void) { TableDeCorrespondance * tnb = new

TableDeCorrespondance(5);

// à la fin : destruction explicite delete tnb;}

Jean-Christophe Engel 32 janvier 2007

Page 33: Jean-Christophe Engel IFSIC - Université Rennes 1...IFSIC – Université Rennes 1 Programmation par objets en C++ Classes Implémentation rationnel.cc importer la définition de

IFSIC – Université Rennes 1 Programmation par objets en C++

Références

définition

● variable, invariable après initialisation, qui désigne de façon non modifiable une autre variable : alias ou nom synonyme de la variable référencée.

● Aucun opérateur ne s'applique directement à une référence : il s'applique toujours à la variable référencée.

initialisation

● Une référence s'initialise toujours avec une variable ou une instance

– la référence est une variable : initialisée dans la déclaration

– la référence est un paramètre formel d'une fonction : initialisée lors de l'appel par le paramètre effectif ; la référence, paramètre formel, désigne le paramètre effectif

– la référence est un attribut d'une classe : initialisée dans le constructeur, obligatoirement par liste d'initialisation.

Jean-Christophe Engel 33 janvier 2007

Page 34: Jean-Christophe Engel IFSIC - Université Rennes 1...IFSIC – Université Rennes 1 Programmation par objets en C++ Classes Implémentation rationnel.cc importer la définition de

IFSIC – Université Rennes 1 Programmation par objets en C++

Références

utilisations principales

● désignation non modifiable d'instances

● paramètres (plus simple que pointeur const)

● surcharges d'opérateurs

référence déclarée comme variable

int i1 = -5, i2 = 6;int & r1 = i1, & r2(i2); // initialisation obligatoire à la déclaration// r1 désigne la variable i1, r2 désigne la variable i2

r1 = 2; // équivaut à i1 = 2r2 = r1; // équivaut à i2 = i1

Rationnel r1(2, 3);Rationnel & rv = r1; // rv et r1 désignent le même Rationnel

● accès attributs et méthodes : opérateur •rv•afficher(); // idem que r1.afficher()

Jean-Christophe Engel 34 janvier 2007

Page 35: Jean-Christophe Engel IFSIC - Université Rennes 1...IFSIC – Université Rennes 1 Programmation par objets en C++ Classes Implémentation rationnel.cc importer la définition de

IFSIC – Université Rennes 1 Programmation par objets en C++

Références

initialisation par création dynamique :

Rationnel & rv = * new Rationnel(2, 3);

indirection (*) obligatoire, car une référence s'initialise avec une instance et non une adresse

● accès attributs et méthodes : opérateur •rv•afficher();

● destructiondelete & rv;

& obligatoire, car delete s'aplique sur une adresse

Jean-Christophe Engel 35 janvier 2007

Page 36: Jean-Christophe Engel IFSIC - Université Rennes 1...IFSIC – Université Rennes 1 Programmation par objets en C++ Classes Implémentation rationnel.cc importer la définition de

IFSIC – Université Rennes 1 Programmation par objets en C++

Références

paramètre formel de fonction :

le paramètre formel désigne le paramètre effectif

● fonctions à paramètres modifiables : l'utilisation des références permet d'alléger la notation mais par ailleurs les fonctions à paramètres modifiables ne rendent pas les programmes très lisibles

avec pointeur avec référencevoid permuter (float * r1, float * r2) { float z;

z = * r1; * r1 = * r2; * r2 = z;}

void permuter (float & r1, float & r2) { float z;

z = r1; r1 = r2; r2 = z;}

appel : float x, y; permuter( & x, & y);

appel : float x, y; permuter( x, y);

l'avantage du passage explicite de l'adresse est qu'on se doute que la fonction va modifier "les paramètres"

l'inconvénient c'est que l'appel masque le fait que la fonction modifie "les paramètres".

Jean-Christophe Engel 36 janvier 2007

Page 37: Jean-Christophe Engel IFSIC - Université Rennes 1...IFSIC – Université Rennes 1 Programmation par objets en C++ Classes Implémentation rationnel.cc importer la définition de

IFSIC – Université Rennes 1 Programmation par objets en C++

Références

● fonctions à paramètres non modifiables : si on ne ne veut pas passer les paramètres par valeur, soit pour des raisons d'économie de temps et de place, soit à cause des problèmes d'affectation de surface : utilisation de const

– par valeurbool Rationnel::estInferieur(Rationnel r) const { return numerateur * r • denominateur < denominateur * r • numerateur;}appel : if (r1.estInferieur(r2)) { ... } // r est une copie de r2

– par pointeurbool Rationnel::estInferieur(const Rationnel * const pr) const { return numerateur * pr → denominateur < denominateur * pr → numerateur;}appel : if (r1.estInferieur(& r2)) { ... } // pr désigne r2

– par référencebool Rationnel::estInferieur(const Rationnel & rr) const { return numerateur * rr • denominateur < denominateur * rr • numerateur;}appel : if (r1.estInferieur(r2)) { ... } // rr désigne r2

Jean-Christophe Engel 37 janvier 2007

Page 38: Jean-Christophe Engel IFSIC - Université Rennes 1...IFSIC – Université Rennes 1 Programmation par objets en C++ Classes Implémentation rationnel.cc importer la définition de

IFSIC – Université Rennes 1 Programmation par objets en C++

Références

résultat de fonction

● une fonction peut renvoyer une référence mais pas sur une variable localeRationnel & Rationnel::max(const Rationnel & ra, const Rationnel & rb){ if (ra.estInferieur(rb)) { return rb; } else { return ra; }}appel : Rationnel & r5 = Rationnel::max(r1, r2);// r5 désigne le plus grand des deux rationnels r1 et r2

● renvoyer une référence sur une variable créée dynamiquement est possible ...Rationnel & Rationnel::somme(const Rationnel & r) const{ return * new Rationnel(numerateur * r•denominateur + denominateur * r•numerateur,

denominateur * r•denominateur);}appel : Rationnel & r5 = r1.somme(r2);// r5 désigne un Rationnel créé dynamiquementdestruction : delete & r5;

... mais, de préférence, renvoyer l'adresse d'une variable allouée dynamiquement

Jean-Christophe Engel 38 janvier 2007

Page 39: Jean-Christophe Engel IFSIC - Université Rennes 1...IFSIC – Université Rennes 1 Programmation par objets en C++ Classes Implémentation rationnel.cc importer la définition de

IFSIC – Université Rennes 1 Programmation par objets en C++

Héritage

● But : exprimer des relations hiérarchiques (similitudes) entre classes, préciser progressivement un ensemble d'attributs et de fonctionnalités et ne reprogrammer que ce qui est nouveau

● exemple :

Jean-Christophe Engel 39 janvier 2007

Cercle

rayon

Point

x y

afficher

Rectangle

hauteurlargeur

Figure

origine

xxx

...

perimetreafficher

perimetreafficher perimetre

afficher

perimetreafficher

Page 40: Jean-Christophe Engel IFSIC - Université Rennes 1...IFSIC – Université Rennes 1 Programmation par objets en C++ Classes Implémentation rationnel.cc importer la définition de

IFSIC – Université Rennes 1 Programmation par objets en C++

Héritage

class Point { double x, y;

public : Point(double x = 0, double y = 0); virtual ~Point(void); virtual void afficher(void) const;};

// constructeurPoint::Point(double a, double b): x(a), y(b) { }

// afficher un pointvoid Point::afficher(void) const { cout << "(" << x << ", " << y << ")";}

class Figure {private: Point origine;

public: Figure(Point o); virtual ~Figure(void); virtual void afficher (void) const; virtual double perimetre(void) const;};

Jean-Christophe Engel 40 janvier 2007

Page 41: Jean-Christophe Engel IFSIC - Université Rennes 1...IFSIC – Université Rennes 1 Programmation par objets en C++ Classes Implémentation rationnel.cc importer la définition de

IFSIC – Université Rennes 1 Programmation par objets en C++

Héritage

class Cercle : public Figure {private: double rayon; // attribut propre de la classe Cercle

public: Cercle(Point centre, double r); // constructeur virtual ~Cercle(void); // destructeur virtual void afficher (void) const; // méthode redéfinie virtual double perimetre(void) const; // méthode redéfinie};

class Rectangle : public Figure {private: double hauteur, largeur; // attributs propres

public: Rectangle(Point coin, double h, double l); // constructeur virtual ~Rectangle(void); // destructeur

// afficher est héritée de Figure virtual double perimetre(void) const; // méthode redéfinie};

Jean-Christophe Engel 41 janvier 2007

Page 42: Jean-Christophe Engel IFSIC - Université Rennes 1...IFSIC – Université Rennes 1 Programmation par objets en C++ Classes Implémentation rationnel.cc importer la définition de

IFSIC – Université Rennes 1 Programmation par objets en C++

Héritage

constructeur

● Les constructeurs ont le nom de la classe ⇒ pas d'héritage des constructeurs.

● Pour initialiser les attributs hérités :

– appeler un constructeur de la classe de base :

implicitement, si la classe de base possède un constructeur sans paramètre

explicitement, si on doit passer des paramètres au constructeur de la classe de base

– dans les listes d'initialisations exclusivement

Jean-Christophe Engel 42 janvier 2007

Page 43: Jean-Christophe Engel IFSIC - Université Rennes 1...IFSIC – Université Rennes 1 Programmation par objets en C++ Classes Implémentation rationnel.cc importer la définition de

IFSIC – Université Rennes 1 Programmation par objets en C++

Héritage

constructeur

● classe FigureFigure::Figure(Point o) : origine(o){}

Figure f(Point(50, 50));// ou bienFigure * pf = new Figure(Point(50, 50));

● classe CercleCercle::Cercle(Point centre, double r) : Figure(centre), rayon(r)

{}

Cercle c(Point(10, 10), 10);// ou bienCercle * pc =

new Cercle(Point(10, 10), 10);

● classe RectangleRectangle::Rectangle(Point coin,

double h, double l)

: Figure(coin), hauteur(h), largeur(l){}

Rectangle r(Point(50, 50), 20, 20);// ou bienRectangle * pr =

new Rectangle(Point(50, 50), 20, 20);

Jean-Christophe Engel 43 janvier 2007

Page 44: Jean-Christophe Engel IFSIC - Université Rennes 1...IFSIC – Université Rennes 1 Programmation par objets en C++ Classes Implémentation rationnel.cc importer la définition de

IFSIC – Université Rennes 1 Programmation par objets en C++

Héritage

méthodes d'une classe dérivée

● méthode héritée : la classe Rectangle hérite de Figure::affichervoid Figure::afficher(void) const { cout << "Figure : origine = " ; origine.afficher(); cout << "périmètre = " << perimetre() << endl;}

r.afficher(); // ou bien pr → afficher();

Figure : origine = (50, 50) périmètre = 80

● méthode surchargée : une méthode d'une classe dérivée peu surcharger une méthode de la classe mère (même nom mais signature paramétrique différente) : l'appel de la méthode adéquate dépend des paramètres effectifs.

Jean-Christophe Engel 44 janvier 2007

Page 45: Jean-Christophe Engel IFSIC - Université Rennes 1...IFSIC – Université Rennes 1 Programmation par objets en C++ Classes Implémentation rationnel.cc importer la définition de

IFSIC – Université Rennes 1 Programmation par objets en C++

Héritage

méthodes d'une classe dérivée

● méthode redéfinie : on peut aussi redéfinir une méthode (même nom, même paramètres, corps différent). Cette nouvelle définition masque la première. Le type de l'instance sur laquelle est appliquée la méthode détermine la méthode appelée. Pour appeler une méthode d'une classe de base redéfinie dans une classe dérivée, il faut la préfixer par sa classe : classe::méthodeC'est le cas de Cercle::afficher

void Cercle::afficher(void) const { Figure::afficher(); // appel de la méthode de la classe de base cout << "Cercle : rayon = " << rayon << endl;}

c.afficher(); // ou bien pc → afficher();

Figure : origine = (10, 10) périmètre = 62.8Cercle : rayon = 10

Jean-Christophe Engel 45 janvier 2007

Page 46: Jean-Christophe Engel IFSIC - Université Rennes 1...IFSIC – Université Rennes 1 Programmation par objets en C++ Classes Implémentation rationnel.cc importer la définition de

IFSIC – Université Rennes 1 Programmation par objets en C++

Héritage

compatibilité des classes

● Une instance d'une classe dérivée peut être utilisée à tout endroit où une instance de sa classe de base publique peut être utilisée.

● De même un pointeur (resp. une référence) sur une instance d'une classe dérivée peut être utilisée à tout endroit où un pointeur (resp. une référence) sur une instance de sa classe de base publique peut être utilisée.

utilité : le polymorphisme

Gérer des instances d'une hiérarchie de classes :

● dont on ne connaît pas forcément toutes les variétés

● qui disposent toutes d'une interface commune : celle de la classe de base

On désigne les instances avec des identificateurs, pointeurs ou références du type « classe de base »

● exemple : collection (tableau, liste,...) de figures géométriques :

– désignés comme « figures »

– afficher un élément de la collection = afficher un cercle, un rectangle...

Jean-Christophe Engel 46 janvier 2007

Page 47: Jean-Christophe Engel IFSIC - Université Rennes 1...IFSIC – Université Rennes 1 Programmation par objets en C++ Classes Implémentation rationnel.cc importer la définition de

IFSIC – Université Rennes 1 Programmation par objets en C++

Héritage

mais... problème de troncature

● Il y a perte d'information lors des opérations suivantes :

– initialisation instance base par instance dérivéeCercle c(Point(10, 10), 10);Figure f(c);f.afficher();

➱ Figure::afficher ➱ Figure::perimetre

– affectation instance base par instance dérivéeRectangle r(Point(50, 50), 20, 20);f = r;f.afficher();

➱ Figure::afficher ➱ Figure::perimetre

– initialisation paramètre par valeur et résultat par valeur

void afficher(Figure f) { f.afficher(); }Cercle c(Point(10, 10), 10);afficher(c);

➱ Figure::afficher➱ Figure::perimetre

Jean-Christophe Engel 47 janvier 2007

Rectangle

origine

hauteur

largeurf = r;

Figure

origine

Page 48: Jean-Christophe Engel IFSIC - Université Rennes 1...IFSIC – Université Rennes 1 Programmation par objets en C++ Classes Implémentation rationnel.cc importer la définition de

IFSIC – Université Rennes 1 Programmation par objets en C++

Héritage

Pour éviter cette perte on désigne les instances par pointeurs ou référence.

liaison dynamique

● Le mécanisme qui permet l'appel de la méthode de la classe de l'instance effective (et non celle de la classe de l'identificateur, du pointeur ou de la référence) s'appelle liaison dynamique.

mais

● Le mécanisme de liaison par défaut de C++ est statique : le choix de la méthode à appeler sur une instance est fait statiquement par le compilateur selon le type déclaré de l'instance (que l'instance soit désignée par identificateur, pointeur ou référence) ; ceci ne permet donc pas de tirer parti pleinement de l'héritage.

☛ Pour profiter pleinement du polymorphisme, il faut :

● déclarer des méthodes virtuelles et

● désigner les instances par pointeur ou référence.

Jean-Christophe Engel 48 janvier 2007

Page 49: Jean-Christophe Engel IFSIC - Université Rennes 1...IFSIC – Université Rennes 1 Programmation par objets en C++ Classes Implémentation rationnel.cc importer la définition de

IFSIC – Université Rennes 1 Programmation par objets en C++

Héritage

class Figure { Point origine;public: Figure(Point o); virtual ~Figure(void) const; virtual double perimetre(void) const; virtual void afficher(void) const;};

Cercle c(Point(10, 10), 10);Figure * pf = &c;pf → perimetre(); // appel de la méthode Cercle::perimetre

Rectangle r(Point(50, 50), 20, 20);Figure & rf(r);rf.perimetre(); // appel de la méthode Rectangle::perimetre

● toute méthode virtuelle

– doit être définie dans la classe de base (sauf si pure)

– peut être redéfinie dans les classes dérivées (de préférence virtuelle)

Jean-Christophe Engel 49 janvier 2007

Page 50: Jean-Christophe Engel IFSIC - Université Rennes 1...IFSIC – Université Rennes 1 Programmation par objets en C++ Classes Implémentation rationnel.cc importer la définition de

IFSIC – Université Rennes 1 Programmation par objets en C++

Héritage

destructeur

● S'il existe des méthodes virtuelles, le destructeur (facultatif, mais hautement recommandé) doit être déclaré virtual et doit être programmé dans la classe de base, même s'il est vide et même dans le cas de classe abstraite. C'est important, car les classes dérivées peuvent ajouter des attributs qui font référence à des données externes qui devront être désallouées proprement.

● L'appel du destructeur d'une classe dérivée entraîne dans un deuxième temps celui de la classe de base.

class Figure { Point origine;public: Figure(Point o); virtual ~Figure(void) const; virtual double perimetre(void) const; virtual void afficher(void) const;};

Figure::~Figure(void) { }

Figure * pf = new Rectangle(...);// appel du constructeur

delete pf;// appel du destructeur ~Rectangle// puis de ~Figure

Jean-Christophe Engel 50 janvier 2007

Page 51: Jean-Christophe Engel IFSIC - Université Rennes 1...IFSIC – Université Rennes 1 Programmation par objets en C++ Classes Implémentation rationnel.cc importer la définition de

IFSIC – Université Rennes 1 Programmation par objets en C++

Héritage

classes abstraites

● définir la méthode Figure::perimetre n'a pas vraiment de sens et créer une instance de la classe Figure non plus

● la classe Figure sert plutôt à définir un ensemble minimal de propriétés (attributs et méthodes) dont on souhaite munir différentes sortes de figures concrètes (cercles, rectangles, etc...).

☛ Cette classe doit donc demeurer une classe abstraite, dont on créera par héritage des classes concrètes.

Jean-Christophe Engel 51 janvier 2007

Page 52: Jean-Christophe Engel IFSIC - Université Rennes 1...IFSIC – Université Rennes 1 Programmation par objets en C++ Classes Implémentation rationnel.cc importer la définition de

IFSIC – Université Rennes 1 Programmation par objets en C++

Héritage

méthode virtuelle pure

● Une méthode virtuelle est dite pure quand elle est initialisée à 0 : elle ne peut donc pas être définie.

class Figure {... virtual double perimetre(void) const = 0; // virtuelle pure};

● Une classe qui comporte (au moins) une méthode virtuelle pure est dite abstraite et il n'est pas possible d'instancier d'instance de cette classe : elle ne peut que servir de classe de base pour d'autres classes. L'intérêt est de fournir une interface en reportant et masquant les détails d'implémentation dans les classes dérivées.

● Une méthode virtuelle pure qui n'est pas définie dans une classe dérivée reste pure, donc la classe dérivée reste aussi abstraite : ceci permet de construire une implémentation par étapes.

Jean-Christophe Engel 52 janvier 2007

Page 53: Jean-Christophe Engel IFSIC - Université Rennes 1...IFSIC – Université Rennes 1 Programmation par objets en C++ Classes Implémentation rationnel.cc importer la définition de

IFSIC – Université Rennes 1 Programmation par objets en C++

Héritage

intérêt du polymorphisme

● collections de classes similaires

– les instances sont gérés par des pointeurs ou des références du type de base

● modules logiciels extensibles

– héritage + méthodes virtuelles permettent d'enrichir des modules déjà programmés :

modification de fonctionnalités

nouvelles variétés de classes

● plusieurs représentations d'un même type abstrait

– optimiser la représentation pour certains cas particuliers (ex : graphe)

méthodes qui dépendent de la représentation : virtuelles

méthodes indépendantes : programmées dans la classe de base

Jean-Christophe Engel 53 janvier 2007

Page 54: Jean-Christophe Engel IFSIC - Université Rennes 1...IFSIC – Université Rennes 1 Programmation par objets en C++ Classes Implémentation rationnel.cc importer la définition de

IFSIC – Université Rennes 1 Programmation par objets en C++

Héritage multiple

● une classse peut hériter de plusieurs classes ; elle possède les attributs et méthodes de toutes les classes dont elle hérite.

class C : public A, public B { // constructeur C( ... ) : A( ... ), B( ... ) { ... }}

● ambiguïtés : si plusieurs classes de base ont des méthodes de même nom, il faut qualifier l'appel de méthode avec le nom de sa classe

● exemple : class Figure {public: Figure(Point o = Point(0, 0)); // constructeur virtual ~Figure(void); // destructeur virtual double perimetre(void) const = 0; // périmètre d'une figure virtual void afficher(void) const; // afficher une Figure

protected : Point origine;};

Jean-Christophe Engel 54 janvier 2007

Page 55: Jean-Christophe Engel IFSIC - Université Rennes 1...IFSIC – Université Rennes 1 Programmation par objets en C++ Classes Implémentation rationnel.cc importer la définition de

IFSIC – Université Rennes 1 Programmation par objets en C++

Héritage multiple

class listePoints {public : listePoints(void); // constructeur sans paramètre virtual ~listePoints(void); // destructeur int getTaille(void) const; // nombre de points de la liste Point operator [] (int i) const; // consulter le point d'indice i void ajoutFin(Point p); // ajouter un point en fin virtual void afficher(void) const; // afficher les points de la liste double longueur(void) const; // longueur de la liste de points

private : int taille; // nombre max de points Point lesPoints[100];};

class Polygone : public Figure, public listePoints {public: Polygone(void); // constructeur pour saisie polygone virtual ~Polygone(void); // destructeur virtual void afficher(void) const; // afficher le polygone virtual double perimetre(void) const; // périmètre du polygone};

Jean-Christophe Engel 55 janvier 2007

Page 56: Jean-Christophe Engel IFSIC - Université Rennes 1...IFSIC – Université Rennes 1 Programmation par objets en C++ Classes Implémentation rationnel.cc importer la définition de

IFSIC – Université Rennes 1 Programmation par objets en C++

Héritage multiple

// afficher un polygone void Polygone::afficher(void) const { Figure::afficher(); // afficher le composant Figure listePoints::afficher(); // afficher le composant listePoints }

● implémentation : à faire

Jean-Christophe Engel 56 janvier 2007

Page 57: Jean-Christophe Engel IFSIC - Université Rennes 1...IFSIC – Université Rennes 1 Programmation par objets en C++ Classes Implémentation rationnel.cc importer la définition de

IFSIC – Université Rennes 1 Programmation par objets en C++

Surcharge des opérateurs

intérêt

● programmation générique avec les outils de la bibliothèque standard

● gestion de la mémoire (constructeur de copie, opérateur =)

constructeur de copie

● rôle : sert à initialiser une instance par une instance de la même classe

– dans une déclaration Rationnel r1(1,2), r2(r1)

– passage par valeur estInferieur(Rationnel r)

– renvoi par une fonction Rationnel max(Rationnel ra, Rationnel rb)

– cas d'un attribut qui est une classeclass CoupleRat { Rationnel origine, extremite; public: CoupleRat(Rationnel o, Rationnel e) : origine(o), extremite(e) {};};

Jean-Christophe Engel 57 janvier 2007

Page 58: Jean-Christophe Engel IFSIC - Université Rennes 1...IFSIC – Université Rennes 1 Programmation par objets en C++ Classes Implémentation rationnel.cc importer la définition de

IFSIC – Université Rennes 1 Programmation par objets en C++

Surcharge des opérateurs

Constructeur de copie

● le constructeur de copie par défaut se contente de copier les attributs des instances (copie de surface).

● Si ce mécanisme par défaut n'est pas satisfaisant (par exemple, si les classes comportent des attributs qui désignent des données allouées dynamiquement), il est nécessaire de programmer son propre constructeur de copie

● exemple : // création d'une première tableTableDeCorrespondance tdc1(25);

// remplissage de la table tdc1// ...

// création d'une table par copie de tdc1TableDeCorrespondance tdc2(tdc1);

Jean-Christophe Engel 58 janvier 2007

Page 59: Jean-Christophe Engel IFSIC - Université Rennes 1...IFSIC – Université Rennes 1 Programmation par objets en C++ Classes Implémentation rationnel.cc importer la définition de

IFSIC – Université Rennes 1 Programmation par objets en C++

Surcharge des opérateurs

Constructeur de copie

Jean-Christophe Engel 59 janvier 2007

constructeur de copie souhaité constructeur de copie par défaut

tdc2

tc

taille

nb

tdc1

tc

taille

nb

tdc2

tdc1

tc

taille

nb

tc

taille

nb

Page 60: Jean-Christophe Engel IFSIC - Université Rennes 1...IFSIC – Université Rennes 1 Programmation par objets en C++ Classes Implémentation rationnel.cc importer la définition de

IFSIC – Université Rennes 1 Programmation par objets en C++

Surcharge des opérateurs

Constructeur de copie

● signature du constructeur de copie pour une classe X donnée : le paramètre est une instance de la classe, obligatoirement passée par référence (si elle est passée par valeur, il y a appel récursif du constructeur de copie ...)

X::X(const X & ix)

class TableDeCorrespondance {public: TableDeCorrespondance (int n = 10); // constructeur TableDeCorrespondance (const TableDeCorrespondance & t); // constructeur de copie ~TableDeCorrespondance(void); // destructeur...};

Jean-Christophe Engel 60 janvier 2007

Page 61: Jean-Christophe Engel IFSIC - Université Rennes 1...IFSIC – Université Rennes 1 Programmation par objets en C++ Classes Implémentation rationnel.cc importer la définition de

IFSIC – Université Rennes 1 Programmation par objets en C++

Surcharge des opérateurs

Constructeur de copie

// constructeur de copie: initialise une table à partir d'une autre// appelé par TableDeCorrespondance t2 = t1; ou TableDeCorrespondance t2(t1);

TableDeCorrespondance::TableDeCorrespondance(const TableDeCorrespondance & t) { copierTable(t);}

// copier dans l'instance courante le contenu de la table passée en paramètrevoid TableDeCorrespondance::copierTable(const TableDeCorrespondance & t) { taille = t.taille; nb = t.nb;

// allouer un nouveau tableau tc = new Couple[taille];

// copier dans l'instance courante le contenu de la table t for (int i = 0; i < nb; ++i) { tc[i] = t.tc[i]; }}

Jean-Christophe Engel 61 janvier 2007

Page 62: Jean-Christophe Engel IFSIC - Université Rennes 1...IFSIC – Université Rennes 1 Programmation par objets en C++ Classes Implémentation rationnel.cc importer la définition de

IFSIC – Université Rennes 1 Programmation par objets en C++

Surcharge des opérateurs

Opérateur d'affectation

Même problème dans le cas de l'affectation : l'opérateur prédéfini se contente d'une affectation de surface.

● exempleTableDeCorrespondance tdc1(25), tdc2(47);...tdc2 = tdc1;

Jean-Christophe Engel 62 janvier 2007

tdc1

tc

taille

nb

tdc2

tc

taille

nb

tdc2

tdc1

tc

taille

nb

tc

taille

nb

opérateur d'affectation par défaut

opérateur d'affectation souhaité

Page 63: Jean-Christophe Engel IFSIC - Université Rennes 1...IFSIC – Université Rennes 1 Programmation par objets en C++ Classes Implémentation rationnel.cc importer la définition de

IFSIC – Université Rennes 1 Programmation par objets en C++

Surcharge des opérateurs

Opérateur d'affectation

Programmation de l'opérateur d'affectation (on suppose qu'on effectue i2 = i1) :

● vérifier si l'instance de droite est égale à celle de gauche : dans ce cas, ne rien faire

● si i2 désigne des données externes, les désallouer au préalable

● allouer de la mémoire fraîche

● y recopier les attributs internes et le contenu des données externes de i1

Ces deux dernières opérations sont communes au constructeur de copie et à l'opérateur d'affectation : on peut en faire une méthode (privée de préférence)...

● signature de l'opérateur d'affectation : X & X::operator = (const X & ix)

l'instance courante est i2 ; l'instance paramètre est i1, passée par référence ;

le résultat est une référence sur l'instance courante, pour pouvoir imbriquer les affectations.

Jean-Christophe Engel 63 janvier 2007

Page 64: Jean-Christophe Engel IFSIC - Université Rennes 1...IFSIC – Université Rennes 1 Programmation par objets en C++ Classes Implémentation rationnel.cc importer la définition de

IFSIC – Université Rennes 1 Programmation par objets en C++

Surcharge des opérateurs

Opérateur d'affectation

TableDeCorrespondance & TableDeCorrespondance::operator = (const TableDeCorrespondance & t){ // égalité entre instance courante et paramètre ? if (this != & t) { // désallouer le tableau de la table courante if (tc != 0) delete [] tc; // idem que pour le constructeur de copie copierTable(t); } return * this; // pour pouvoir enchaîner les affectations}

● désignation de l'instance courante : this

dans toute classe X, this est un pointeur (type X *) qui désigne l'instance courante.

Jean-Christophe Engel 64 janvier 2007

Page 65: Jean-Christophe Engel IFSIC - Université Rennes 1...IFSIC – Université Rennes 1 Programmation par objets en C++ Classes Implémentation rationnel.cc importer la définition de

IFSIC – Université Rennes 1 Programmation par objets en C++

Surcharge des opérateurs

Opérateurs binaires : + * ... [ ] ( )

un opérateur binaire @ peut être redéfini de deux façons :

● comme méthode : i1 @ i2 est traduit en i1.operator @(i2)

il faut donc que i1 soit une instance d'une classe X, et @ une méthode de la classe Xclass X { typeResultat operator @(const X & i2); // modifie l'instance i1 typeResultat operator @(const X & i2) const; // ne modifie pas l'instance i1}

● comme fonction : i1 @ i2 est traduit en operator @(i1, i2)

dans ce cas, il faut que la fonction ait accès aux attributs de la classe X typeResultat operator @(X & i1, const X & i2); // modifie i1 typeResultat operator @(const X & i1, const X & i2); // ne modifie pas i1

Jean-Christophe Engel 65 janvier 2007

Page 66: Jean-Christophe Engel IFSIC - Université Rennes 1...IFSIC – Université Rennes 1 Programmation par objets en C++ Classes Implémentation rationnel.cc importer la définition de

IFSIC – Université Rennes 1 Programmation par objets en C++

Surcharge des opérateurs

Opérateurs binaires : + * ... [ ] ( )

● exemples

– somme de 2 rationnels programmée par une méthodeRationnel Rationnel::operator + (const Rationnel & r) const{ return Rationnel(numerateur * r.denominateur + denominateur * r.numerateur,

denominateur * r.denominateur);}

– somme de 2 rationnels programmée par une fonctionRationnel operator + (const Rationnel & r1, const Rationnel & r2){ return Rationnel( r1.getNumerateur() * r2.getDenominateur() +

r1.getDenominateur() * r2.getNumerateur(),r1.getDenominateur() * r2.getDenominateur());

}

// appelRationnel r1(1, 3), r2(4, 5), rs(r1 + r2);

Jean-Christophe Engel 66 janvier 2007

Page 67: Jean-Christophe Engel IFSIC - Université Rennes 1...IFSIC – Université Rennes 1 Programmation par objets en C++ Classes Implémentation rationnel.cc importer la définition de

IFSIC – Université Rennes 1 Programmation par objets en C++

Surcharge des opérateurs

● exemples (suite)

– comparaison :// comme méthodebool Rationnel::operator < (const Rationnel & r) const { .. }

// comme fonctionbool operator < (const Rationnel & r1, const Rationnel & r2) { .. }

– produit d'un rationnel par un entier : il faut penser à la commutativité// Rationnel * entier : fonction ou méthode de la classe RationnelRationnel Rationnel::operator * (int r) { return Rationnel(r * getNumerateur(), getDenominateur()); }

//entier * Rationnel : obligatoirement fonctionRationnel operator * (int r, const Rationnel & rat) { return Rationnel(r * rat.getNumerateur(), rat.getDenominateur()); }

Jean-Christophe Engel 67 janvier 2007

Page 68: Jean-Christophe Engel IFSIC - Université Rennes 1...IFSIC – Université Rennes 1 Programmation par objets en C++ Classes Implémentation rationnel.cc importer la définition de

IFSIC – Université Rennes 1 Programmation par objets en C++

Surcharge des opérateurs

Opérateurs unaires : ++ -- - * & ! →

un opérateur unaire @ peut être redéfini de deux façons :

● comme méthode : @ a est traduit en a.operator @()class X { typeResultat operator @(); // modifie l'instance a typeResultat operator @() const; // ne modifie pas l'instance a}

● comme fonction : @ a est traduit en operator @(a) typeResultat operator @(X & a); // modifie a typeResultat operator @(const X & a); // ne modifie pas a

Jean-Christophe Engel 68 janvier 2007

Page 69: Jean-Christophe Engel IFSIC - Université Rennes 1...IFSIC – Université Rennes 1 Programmation par objets en C++ Classes Implémentation rationnel.cc importer la définition de

IFSIC – Université Rennes 1 Programmation par objets en C++

Surcharge des opérateurs

Opérateurs unaires : cas de ++ et --

● comme méthode :class X { // opérateur préfixé : ++x traduit en x.operator ++() // résultat obligatoirement par référence X & operator ++();

// opérateur postfixé : x++ traduit en x.operator ++(int) // résultat de préférence par valeur (ou bien aucun résultat) X operator ++(int x); // paramètre entier bidon}

● comme fonction :// opérateur préfixé : ++x traduit en operator ++(a)X & operator ++(X & a);

// opérateur postfixé : x++ traduit en operator ++(a, int)X operator ++(X & a, int x);

Jean-Christophe Engel 69 janvier 2007

Page 70: Jean-Christophe Engel IFSIC - Université Rennes 1...IFSIC – Université Rennes 1 Programmation par objets en C++ Classes Implémentation rationnel.cc importer la définition de

IFSIC – Université Rennes 1 Programmation par objets en C++

Surcharge des opérateurs

Opérateurs unaires : cas de ++ et --

● exemple

// opérateur ++ préfixéRationnel & Rationnel::operator ++ () {* this = * this + Rationnel(1); // *this = *this + 1; ???

// ou bien : numerateur += denominateur; return * this;}

// opérateur ++ postfixéRationnel operator ++ (Rationnel & r, int x) { Rationnel ancien(r) r = r + Rationnel(1); // r = r + 1; ??? return ancien;}

// appelRationnel r1(3, 5), r2(-2, 3);++r1; // r1 vaut 8/5r2++; // r2 vaut 1/3

Jean-Christophe Engel 70 janvier 2007

Page 71: Jean-Christophe Engel IFSIC - Université Rennes 1...IFSIC – Université Rennes 1 Programmation par objets en C++ Classes Implémentation rationnel.cc importer la définition de

IFSIC – Université Rennes 1 Programmation par objets en C++

Surcharge des opérateurs

Cas des opérateurs d'entrée/sortie

● Ces opérateurs sont définis respectivement dans les classes istream ( >> ) et ostream ( << ).

☛la surcharge se fait avec une fonction qui prend en paramètre une instance d'(i/o)stream et une instance de l'objet à lire/écrire.

● Ces opérateurs renvoient une instance de leur opérande gauche (classe (i/o)stream) afin de permettre l'imbrication de leurs appels :

cout << a << b ⇔ cout << a ; cout << b ;

// surcharge de <<ostream & operator << (ostream & sortie, const Rationnel & r) { sortie << r.getNumerateur(); if (r.getDenominateur() != 1) { sortie << "/" << r.getDenominateur(); } return sortie;}// appelRationnel r1(1, 2), r2(2, 3); cout << r1 << " + " << r2 << " = " << r1 + r2;

Jean-Christophe Engel 71 janvier 2007

Page 72: Jean-Christophe Engel IFSIC - Université Rennes 1...IFSIC – Université Rennes 1 Programmation par objets en C++ Classes Implémentation rationnel.cc importer la définition de

IFSIC – Université Rennes 1 Programmation par objets en C++

Exceptions

but : traiter les cas exceptionnels sans alourdir les cas normaux

● déclenchement d'exception : throw e;

e est une expression de type quelconque :

– type prédéfini : int(23), string("Division par zéro !!")

– type défini par l'utilisateur : class Erreur { ... };

– type dérivé d'un type standard : class Erreur : public domain_error { ... };

● traitement d'exception :try {

instructions qui peuvent déclencher une exception

} catch (typeException1 & e1) { // exception la moins généraletraitement de e1

} catch (typeException2 & e2) {traitement de e2

} ...

} catch (typeExceptionn & en) { // exception la plus généraletraitement de en

}

Jean-Christophe Engel 72 janvier 2007

Page 73: Jean-Christophe Engel IFSIC - Université Rennes 1...IFSIC – Université Rennes 1 Programmation par objets en C++ Classes Implémentation rationnel.cc importer la définition de

IFSIC – Université Rennes 1 Programmation par objets en C++

Exceptions

● exemple avec un type prédéfiniRationnel::Rationnel(int num, int den) throw (string) : numerateur(num), denominateur(den){ if (denominateur == 0) throw string("Division par zéro !!"); normaliser();}

Rationnel nb, inverse;try { inverse = nb.inverse(); // traitement normal de inverse

...

} catch (string & msg) { cerr << msg << endl;}

● simple à mettre en oeuvre

● difficile de distinguer les différentes catégories d'exception : une erreur de nature complètement différente peut déclencher une exception du même type.

Jean-Christophe Engel 73 janvier 2007

Page 74: Jean-Christophe Engel IFSIC - Université Rennes 1...IFSIC – Université Rennes 1 Programmation par objets en C++ Classes Implémentation rationnel.cc importer la définition de

IFSIC – Université Rennes 1 Programmation par objets en C++

Exceptions

● exemple avec un type défini par l'utilisateurclass Erreur {public : Erreur(const string & msg) : cause(msg) {}; const string what (void) { return cause; };private: string cause;};

Rationnel::Rationnel(int num, int den) throw (Erreur) : numerateur(num), denominateur(den) { if (denominateur == 0) throw Erreur("Division par zéro !!"); normaliser();}

try { inverse = nb.inverse(); // traitement normal de inverse} catch (Erreur & e) { cerr << e.what() << endl;}

☛ meilleure classification des différentes erreurs gérées par exception.

Jean-Christophe Engel 74 janvier 2007

Page 75: Jean-Christophe Engel IFSIC - Université Rennes 1...IFSIC – Université Rennes 1 Programmation par objets en C++ Classes Implémentation rationnel.cc importer la définition de

IFSIC – Université Rennes 1 Programmation par objets en C++

Exceptions

● solution avec classe dérivée d'un type standard#include <stdexcept> // bibliothèque standard d'exceptions

class Erreur : public domain_error {public : Erreur(const string & msg) : domain_error(msg) { };};

Rationnel::Rationnel(int num, int den) throw (Erreur) : numerateur(num), denominateur(den) { if (denominateur == 0) throw Erreur("Division par zéro !!"); normaliser();}

try { inverse = nb.inverse(); // traitement normal de inverse}catch (Erreur & e) { cerr << e.what() << endl; }

☛ classification standard d'un grand nombre d'erreurs.

Jean-Christophe Engel 75 janvier 2007

Page 76: Jean-Christophe Engel IFSIC - Université Rennes 1...IFSIC – Université Rennes 1 Programmation par objets en C++ Classes Implémentation rationnel.cc importer la définition de

IFSIC – Université Rennes 1 Programmation par objets en C++

Généricité - Modèles

● but : faire de la programmation générique, c'est-à-dire utiliser des types pour paramétrer la définition des classes et des fonctions.

● technique intensivement utilisée dans la bibliothèque standard

● exemple : fonction dont les paramètres sont d'un type T quelconquetemplate <class T> const T & plusgrand(const T & x, const T & y){ if (x > y) { return x; } else { return y; }}

... int i(3), j(5); cout << "le max de " << i << " et " << j << " = " << plusgrand(i, j) << endl; // le max de 3 et 5 = 5

Rationnel r1(1, 2), r2(3, 4); cout << "le max de " << r1 << " et " << r2 << " = " << plusgrand(r1, r2) << endl; // le max de 1/2 et 3/4 = 3/4

☛ contrainte implicite : l'opérateur > doit être défini sur les valeurs du type T

Jean-Christophe Engel 76 janvier 2007

Page 77: Jean-Christophe Engel IFSIC - Université Rennes 1...IFSIC – Université Rennes 1 Programmation par objets en C++ Classes Implémentation rationnel.cc importer la définition de

IFSIC – Université Rennes 1 Programmation par objets en C++

Modèles de classe (templates)

● couple génériquetemplate <class T1, class T2>class Couple { private: T1 comp1; T2 comp2; // constructeur Couple(const T1 & v1 = T1(), const T2 & v2 = T2()); // accesseurs const T1 & getPremier() const; const T1 & getDeuxieme() const; void setPremier (const & T1 v); void setDeuxieme(const & T1 v);};

// implémentationtemplate <class T1, class T2>Couple<T1, T2>::Couple(const T1 & v1, const T2 & v2) : comp1(v1), comp2(v2) { }

template <class T1, class T2>Couple<T1, T2>::setPremier(const & T1 v) { comp1 = v; }

☛ contraintes sur les types Tcle et Tval : constructeur sans paramètre et opérateur =

Jean-Christophe Engel 77 janvier 2007

Page 78: Jean-Christophe Engel IFSIC - Université Rennes 1...IFSIC – Université Rennes 1 Programmation par objets en C++ Classes Implémentation rationnel.cc importer la définition de

IFSIC – Université Rennes 1 Programmation par objets en C++

Modèles de classe (templates)

● table dont les éléments sont d'un type quelconquetemplate <class Tcle, class Tval>class TableDeCorrespondance {public: TableDeCorrespondance (int); void debut (void) const; // indépendant de Tcle et Tval // ... const Tcle & getCle (void) const; const Tval & getValeur(void) const; bool estPresent (const Tcle & cle) const; void modifier (const Tcle & cle, const Tval & valeur); // ...private: Couple<Tcle, Tval> * tc; int taille, nb;};// fonction d'affichagetemplate <class Tcle, class Tval> ostream & operator << (ostream & sortie, const TableDeCorrespondance<Tcle,Tval> & t);

☛ contraintes sur les types Tcle et Tval : définies par les opérations appliquées sur les valeurs des types Tcle et Tval.

Jean-Christophe Engel 78 janvier 2007

Page 79: Jean-Christophe Engel IFSIC - Université Rennes 1...IFSIC – Université Rennes 1 Programmation par objets en C++ Classes Implémentation rationnel.cc importer la définition de

IFSIC – Université Rennes 1 Programmation par objets en C++

Modèles de classe

● implémentation (tdc.cc)// constructeurtemplate <class Tcle, class Tval>TableDeCorrespondance<Tcle, Tval>::TableDeCorrespondance(int n) : tc(new Couple<Tcle,Tval>[taille]), taille(n), nb(0) { }

// modifier un élémenttemplate <class Tcle, class Tval>TableDeCorrespondance<Tcle, Tval>::modifier(const Tcle & cle, const Tval & valeur) { if (estPresent(cle)) { // clé présente tc[courant].setDeuxieme(valeur); // on modifie la valeur associée }}

● utilisation (client.cc)#include "tdc.cc"... TableDeCorrespondance<string, int> pf(8); TableDeCorrespondance<string, Rationnel> pr(15);

☛ pour chaque déclaration différente de table, le compilateur instancie un exemplaire de table, donc a besoin de (re)compiler sa définition.

Jean-Christophe Engel 79 janvier 2007

Page 80: Jean-Christophe Engel IFSIC - Université Rennes 1...IFSIC – Université Rennes 1 Programmation par objets en C++ Classes Implémentation rationnel.cc importer la définition de

IFSIC – Université Rennes 1 Programmation par objets en C++

Bibliothèque standard

fonctionnalités :

● gestion de mémoire, informations de types à l'exécution

● bibliothèque standard C

● chaînes et entrées/sorties

● bibliothèque de modèles (STL)

– gestion de collections d'instances (conteneurs)

– algorithmes efficaces de traitement

● support du traitement numérique (complexes, vecteurs avec opérations arithmétiques)

● internationalisation

Jean-Christophe Engel 80 janvier 2007

Page 81: Jean-Christophe Engel IFSIC - Université Rennes 1...IFSIC – Université Rennes 1 Programmation par objets en C++ Classes Implémentation rationnel.cc importer la définition de

IFSIC – Université Rennes 1 Programmation par objets en C++

Bibliothèque de modèles (STL)

conteneur

● structure de données (collection) de taille variable qui contient des éléments. Un conteneur est paramétré par la classe des éléments qu'il contient (template).

● chaque type de conteneur a des avantages et des inconvénients (ajout, retrait, recherche) : la variété de conteneurs permet au programmeur de choisir les outils adaptés à son problème.

– exemples : vecteur, liste, file, tableaux associatifs, ensemble, multi-ensemble

– opérations : ajout, suppression, ...

itérateur

classe qui permet d'accéder aux éléments d'un conteneur donné ; interface commune à tous les itérateurs et proche de celle des pointeurs (*, ++, ...)

algorithmes

servent à traiter les éléments d'un conteneur : recherche, tri, fusion, modification ; indépendants des conteneurs, liaison faite par itérateur

Jean-Christophe Engel 81 janvier 2007

Page 82: Jean-Christophe Engel IFSIC - Université Rennes 1...IFSIC – Université Rennes 1 Programmation par objets en C++ Classes Implémentation rationnel.cc importer la définition de

IFSIC – Université Rennes 1 Programmation par objets en C++

Les conteneurs

deux grandes catégories :

● conteneurs séquentiels : les éléments sont placés de façon séquentielle dans le conteneur ; leur position ne dépend pas de leur valeur ; vector, deque, list.

● conteneurs associatifs : collection triée d'éléments : la position de chaque élément dépend d'un critère de tri et non de l'ordre d'insertion.

● NB : il est possible de trier un conteneur séquentiel

● un conteneur associatif offre de meilleures performances en recherche

Jean-Christophe Engel 82 janvier 2007

vector

deque

list

set/multiset

map/multimap

Page 83: Jean-Christophe Engel IFSIC - Université Rennes 1...IFSIC – Université Rennes 1 Programmation par objets en C++ Classes Implémentation rationnel.cc importer la définition de

IFSIC – Université Rennes 1 Programmation par objets en C++

Conteneurs séquentiels

tableau (vector)

● gère ses éléments dans un tableau dynamique

● accès direct aux éléments par opérateur [ ] et indice

● ajout/retrait en fin très rapide (push_back, pop_back)

● ajout/retrait ailleurs oblige à déplacer les éléments qui suivent : lent

● exemple :#include <vector>using namespace std;...vector<Rationnel> vecteurRat;

for (int i = 1; i <= 5; ++i) { vecteurRat.push_back(Rationnel(i, 7)); // ajout en fin du conteneur}

for (int i = 0; i < vecteurRat.size(); ++i) { // afficher les éléments cout << vecteurRat[i] << ' ';}cout << endl;

Jean-Christophe Engel 83 janvier 2007

Page 84: Jean-Christophe Engel IFSIC - Université Rennes 1...IFSIC – Université Rennes 1 Programmation par objets en C++ Classes Implémentation rationnel.cc importer la définition de

IFSIC – Université Rennes 1 Programmation par objets en C++

Conteneurs séquentiels

file à deux têtes (deque)

● tableau dynamique qui peut grandir aux deux extrémités

● accès direct aux éléments par opérateur [ ] et indice

● ajout/retrait en début et en fin très rapide (push_front, push_back, pop_xxx)

● ajout/retrait ailleurs oblige à déplacer les éléments : lent

● exemple :#include <deque>using namespace std;...deque<Rationnel> dequeRat;

for (int i = 1; i <= 5; ++i) { dequeRat.push_front(Rationnel(i, 7)); // ajout en début du conteneur}

for (int i = 0; i < dequeRat.size(); ++i) { // afficher les éléments cout << dequeRat[i] << ' ';}cout << endl;

Jean-Christophe Engel 84 janvier 2007

Page 85: Jean-Christophe Engel IFSIC - Université Rennes 1...IFSIC – Université Rennes 1 Programmation par objets en C++ Classes Implémentation rationnel.cc importer la définition de

IFSIC – Université Rennes 1 Programmation par objets en C++

Conteneurs séquentiels

liste (list)

● liste doublement chaînée d'éléments

● pas d'accès direct aux éléments (donc pas d'opérateur [ ]) :

– accès au ième élément requiert un parcours séquentiel des i-1 premiers (long)

– passage d'un élément au suivant ou au précédent en temps constant

● ajout/retrait en toute position très rapide (insert, remove)

● exemple :#include <list>using namespace std;list<Rationnel> listeRat;

for (int i = 1; i <= 5; ++i) { listeRat.push_back(Rationnel(i, 7)); // ajout en fin du conteneur}while (! listeRat.empty()) { // tantque non vide cout << listeRat.front() << ' '; // afficher l'élément de tête listeRat.pop_front(); // et l'ôter du conteneur}cout << endl;

Jean-Christophe Engel 85 janvier 2007

Page 86: Jean-Christophe Engel IFSIC - Université Rennes 1...IFSIC – Université Rennes 1 Programmation par objets en C++ Classes Implémentation rationnel.cc importer la définition de

IFSIC – Université Rennes 1 Programmation par objets en C++

Conteneurs associatifs

● un conteneur associatif trie automatiquement ses éléments selon un critère d'ordre : fonction qui compare soit la valeur de deux éléments soit celle de clés.

● par défaut, la fonction de comparaison est l'opérateur <

● accès aux éléments requiert des itérateurs

● implémentation : arbre binaire trié

– temps d'accès proportionnel à la hauteur de l'arbre (log2(n))

– techniques très efficaces pour équilibrer des arbres

● ensemble (set) : collection dont les éléments sont triés selon leur valeur ; chaque élément n'apparait qu'une fois.

● multi-ensemble (multiset) : idem, mais occurrences multiples autorisées (1, 1, 3, 5, 5, 7, 10)

● tableau associatif (map) : contient des paires <clé, valeur> ; la clé sert de critère de tri et doit être unique (<"jacques", 10>, <"paul", 5> ...)

● dictionnaire (multimap) : idem mais les clés multiples sont autorisées

Jean-Christophe Engel 86 janvier 2007

7

10

2 5 8 12

3

Page 87: Jean-Christophe Engel IFSIC - Université Rennes 1...IFSIC – Université Rennes 1 Programmation par objets en C++ Classes Implémentation rationnel.cc importer la définition de

IFSIC – Université Rennes 1 Programmation par objets en C++

Itérateurs

● classe qui permet d'accéder aux éléments d'un conteneur

● opérations fondamentales (semblables aux pointeurs)

* : donne la valeur de l'élément courant (celui désigné par l'itérateur)

→ : accès aux attributs et méthodes de l'élément courant, s'il en a

++ : fait progresser l'itérateur à l'élément suivant (quel que soit le type du conteneur auquel est associé l'itérateur) ; la plupart des conteneurs permettent aussi --.

== != : comparaisons de deux itérateurs

= : affectation de deux itérateurs

● Quelques méthodes de base communes aux conteneurs :

begin() : itérateur qui désigne le premier élément d'un conteneur

end() : itérateur situé après la fin d'un conteneur

Jean-Christophe Engel 87 janvier 2007

end() begin()

Page 88: Jean-Christophe Engel IFSIC - Université Rennes 1...IFSIC – Université Rennes 1 Programmation par objets en C++ Classes Implémentation rationnel.cc importer la définition de

IFSIC – Université Rennes 1 Programmation par objets en C++

Itérateurs

● exemple :#include <list>using namespace std;

list<Rationnel> listeRat;

list<Rationnel>::iterator iratio = listeRat.begin();// permet de désigner des éléments dans une liste de rationnels

while(iratio != listeRat.end()) { cout << * iratio << " "; ++iratio;}cout << endl;

● chaque conteneur définit (au moins) deux types d'itérateurs :

– conteneur::iterator : accès aux éléments en consultation/modification

– conteneur::const_iterator : accès aux éléments en consultation seule

● les éléments compris entre begin() (inclus) et end() (exclu) forment une séquence ; une séquence est vide si l'itérateur de début = l'itérateur de fin

Jean-Christophe Engel 88 janvier 2007

Page 89: Jean-Christophe Engel IFSIC - Université Rennes 1...IFSIC – Université Rennes 1 Programmation par objets en C++ Classes Implémentation rationnel.cc importer la définition de

IFSIC – Université Rennes 1 Programmation par objets en C++

Itérateurs et conteneurs associatifs

ensemble (set/multiset)

#include <set>

typedef set<Rationnel> ensembleRationnel; // définition du type du conteneurensembleRationnel ensrat; // déclaration de l'ensemble

// ajout d'élémentsensrat.insert(Rationnel(1, 3)); // ajout "à sa place" si possible ...

// affichage des élémentsensembleRationnel::const_iterator criter; // itérateurfor (criter = ensrat.begin() ; criter != ensrat.end(); ++criter) { cout << * criter << " ";}

● typedef set<Rationnel> ensembleRationnel : utilise l'opérateur < pour comparer deux rationnels

● typedef set<Rationnel, greater<Rationnel> > ensembleRationnel : utilise la fonction générique prédéfinie greater<> pour comparer deux rationnels : exige que l'opérateur > soit défini sur les rationnels.

Jean-Christophe Engel 89 janvier 2007

Page 90: Jean-Christophe Engel IFSIC - Université Rennes 1...IFSIC – Université Rennes 1 Programmation par objets en C++ Classes Implémentation rationnel.cc importer la définition de

IFSIC – Université Rennes 1 Programmation par objets en C++

Itérateurs et conteneurs associatifs

tableaux associatifs (map/multimap)

#include <map>typedef multimap<int, string> TassocIS; // type du tableau associatif

TassocIS tass; int nb; string txt;

cin >> nb >> txt; // lire une clé et la valeur associée tass.insert(make_pair(nb, txt)); // faire un doublet pour l'insérer... // afficher le contenu TassocIS::const_iterator imap = tass.begin(); while (imap != tass.end()) { cout << "clé : " << imap → first << ", valeur : " << imap → second << endl; ++imap; }

● les éléments sont des doublets <clé, valeur> qu'il faut créer avec make_pair

● les itérateurs désignent des doublets dont on obtient les composantes avec first et second

Jean-Christophe Engel 90 janvier 2007

Page 91: Jean-Christophe Engel IFSIC - Université Rennes 1...IFSIC – Université Rennes 1 Programmation par objets en C++ Classes Implémentation rationnel.cc importer la définition de

IFSIC – Université Rennes 1 Programmation par objets en C++

Algorithmes

la STL dispose de nombreux algorithmes standards :

● algorithmes qui ne modifient ni les conteneurs ni leurs éléments :

– comptage, min, max, recherche...

● algorithmes qui modifient les éléments :

– remplacement, suppression

● algorithmes qui modifient l'ordre des éléments sans modifier leur valeur :

– permutation (circulaire ou non), tri, fusion, copie

● algorithmes numériques

– combinaison des élts par différents opérateurs arithmétiques (+, *, - ...)

Ces algorithmes sont des fonctions (pas des méthodes) indépendantes des conteneurs auxquels ils accèdent par l'intermédiaire des itérateurs.

avantage : implémentation unique d'un algorithme, indépendance par rapport au conteneur, généricité de la programmation

inconvénient : ne tirent pas parti des caractéristiques de chaque conteneur : certains algorithmes sont doublés de méthodes qui opèrent plus efficacement

Jean-Christophe Engel 91 janvier 2007

Page 92: Jean-Christophe Engel IFSIC - Université Rennes 1...IFSIC – Université Rennes 1 Programmation par objets en C++ Classes Implémentation rationnel.cc importer la définition de

IFSIC – Université Rennes 1 Programmation par objets en C++

Algorithmes

● exemple d'algorithme générique : sort

– trier un conteneur par ordre croissant à l'aide de l'opérateur < qui doit être défini pour les éléments du conteneur.

#include <vector>#include <algorithm>using namespace std;...vector<Rationnel> vecteurRat;...sort(vecteurRat.begin(), vecteurRat.end());// trie les éléments situés entre vecteurRat.begin() et vecteurRat.end()

– idem avec une fonction de comparaisonsort(vecteurRat.begin(), vecteurRat.end(), comparerDenominateurs);// les éléments sont comparés avec la fonction comparerDenominateurs...bool comparerDenominateurs(const Rationnel & r1, const Rationnel & r2) { return r1.denominateur < r2.denominateur;}

Jean-Christophe Engel 92 janvier 2007

Page 93: Jean-Christophe Engel IFSIC - Université Rennes 1...IFSIC – Université Rennes 1 Programmation par objets en C++ Classes Implémentation rationnel.cc importer la définition de

IFSIC – Université Rennes 1 Programmation par objets en C++

Itérateurs spéciaux

itérateurs d'insertion

● accèdent aux conteneurs en mode insertion et non en mode remplacement

– donner une valeur à l'élément désigné par un itérateur d'insertion insère la valeur dans le conteneur

– l'opération "avancer" (++) n'a aucun effetlist<Rationnel> listeRat;// ajout d'éléments dans la liste...for (int i = 1; i <= 10; ++i) { listeRat.push_back(Rationnel(i, 7); }

// copie dans un vecteurvector<Rationnel> vecteurRat;copy(listeRat.begin(), listeRat.end(), vecteurRat.begin());

● l'algorithme copy copie les données d'une séquence dans une autre :

– séquence d'origine : listeRat.begin(), listeRat.end()

– séquence destination : vecteurRat.begin()

Problème : copy remplace les données de la séquence destination... or ici, le conteneur est vide, d'où échec à l'exécution

Jean-Christophe Engel 93 janvier 2007

Page 94: Jean-Christophe Engel IFSIC - Université Rennes 1...IFSIC – Université Rennes 1 Programmation par objets en C++ Classes Implémentation rationnel.cc importer la définition de

IFSIC – Université Rennes 1 Programmation par objets en C++

Itérateurs spéciaux

itérateurs d'insertion (suite)

● solution : utiliser un itérateur d'insertion : back_inserter, front_inserter ou inserter

// insertion en fincopy(listeRat.begin(), listeRat.end(), back_inserter(vecteurRat));

// insertion en tête (et en ordre inverse)deque<Rationnel> dequeRat;copy(listeRat.begin(), listeRat.end(), front_inserter(dequeRat));

// insertion avant la position désignéeset<Rationnel> ensembleRat;copy(listeRat.begin(), listeRat.end(), inserter(ensembleRat, ensembleRat.begin()));

● back_inserter : insère les éléments à la fin du conteneur avec push_back() ; fonctionne avec vector, deque et list.

● front_inserter : insère les éléments en tête du conteneur avec push_front() ; fonctionne avec deque et list.

● inserter : insère les éléments avant la position passée en deuxième argument par appel de la méthode insert du conteneur ; fonctionne avec tous les conteneurs

Jean-Christophe Engel 94 janvier 2007

Page 95: Jean-Christophe Engel IFSIC - Université Rennes 1...IFSIC – Université Rennes 1 Programmation par objets en C++ Classes Implémentation rationnel.cc importer la définition de

IFSIC – Université Rennes 1 Programmation par objets en C++

Itérateurs spéciaux

itérateurs de flux

permettent de considérer le fichier d'entrée comme un conteneur duquel on peut lire des données et le fichier de sortie comme un conteneur dans lequel écrire.vector<Rationnel> vecteurRat;

// insérer les données lues sur l'entrée standard dans le vecteurcopy( istream_iterator<Rationnel>(cin), // début de la séquence origine

istream_iterator<Rationnel>(), // fin de la séquence origineback_inserter(vecteurRat)); // début de la séquence destination

// copier (sans doublons) le contenu du vecteur sur la sortie standardunique_copy( vecteurRat.begin(), vecteurRat.end(), // séquence origine

ostream_iterator<Rationnel>(cout, " ")); // destination

● istream_iterator<Rationnel>(cin) : crée un itérateur qui lit depuis le fichier cin ; chaque opération de progression de l'itérateur lit un nouveau rationnel avec >>

● istream_iterator<Rationnel>() : crée un itérateur de "fin de fichier"

● ostream_iterator<Rationnel>(cout, " ") : crée un itérateur qui écrit dans le fichier cout avec <<.

Jean-Christophe Engel 95 janvier 2007

Page 96: Jean-Christophe Engel IFSIC - Université Rennes 1...IFSIC – Université Rennes 1 Programmation par objets en C++ Classes Implémentation rationnel.cc importer la définition de

IFSIC – Université Rennes 1 Programmation par objets en C++

Itérateurs spéciaux

itérateurs inverses

opérent "à l'envers" des itérateurs standards : l'opérateur ++ les fait passer à l'élément précédent.// affiche les éléments du conteneur "en ordre inverse" : du dernier au premierfor (criter = cont.rbegin() ; criter != cont.rend(); ++criter) { cout << * criter << " ";}

// idem avec l'algorithme copy et l'itérateur de sortiecopy( vecteurRat.rbegin(), vecteurRat.rend(), // séquence origine

ostream_iterator<Rationnel>(cout, " ")); // destination

Jean-Christophe Engel 96 janvier 2007

Page 97: Jean-Christophe Engel IFSIC - Université Rennes 1...IFSIC – Université Rennes 1 Programmation par objets en C++ Classes Implémentation rationnel.cc importer la définition de

IFSIC – Université Rennes 1 Programmation par objets en C++

Fonctions génériques

manipulation de conteneurs

● fonction générique qui opère sur un conteneur, paramètre du modèle

● utilisation d'itérateur pour accéder aux éléments du conteneur

exemple : afficher le contenu d'un conteneur quelconque avec un itérateurtemplate <class Conteneur>void afficherConteneur(const Conteneur & crat) {

cout << "<"; typename Conteneur::const_iterator criter = crat.begin(); while (criter != crat.end()) { cout << * criter << " "; ++criter; } cout << ">\n";}

● typename Conteneur::const_iterator criter☛ exige que la classe Conteneur définisse un type const_iterator.

typename signifie que Conteneur::const_iterator est un type et non un attribut

Jean-Christophe Engel 97 janvier 2007

Page 98: Jean-Christophe Engel IFSIC - Université Rennes 1...IFSIC – Université Rennes 1 Programmation par objets en C++ Classes Implémentation rationnel.cc importer la définition de

IFSIC – Université Rennes 1 Programmation par objets en C++

Fonctions en paramètres

● But : paramétrer certains algorithmes avec une fonction// trier le tableau avec l'algorithme sort et l'opérateur <sort(vecteurRat .begin(), vecteurRat.end());

bool comparerNumerateurs(const Rationnel & r1, const Rationnel & r2) { return r1.getNumerateur() < r2.getNumerateur();}

// trier le tableau avec la fonction comparerNumerateurssort(vecteurRat .begin(), vecteurRat.end(), comparerNumerateurs);

static bool Rationnel::comparerDenominateurs(const Rationnel & r1, const Rationnel & r2){ return r1.getDenominateur() < r2.getDenominateur();}

// trier le tableau avec la méthode Rationnel::comparerDenominateurssort(vecteurRat .begin(), vecteurRat.end(), Rationnel::comparerDenominateurs);

Jean-Christophe Engel 98 janvier 2007

Page 99: Jean-Christophe Engel IFSIC - Université Rennes 1...IFSIC – Université Rennes 1 Programmation par objets en C++ Classes Implémentation rationnel.cc importer la définition de

IFSIC – Université Rennes 1 Programmation par objets en C++

Objet fonctionnel

classe qui se comporte comme une fonction : appel avec des () et des paramètres

mafonction(param1, param2) traduit en mafonction.operator () (param1, param2)

exemple :class Affiche {public: void operator () (const Rationnel & r) const { cout << r; }};

// afficher le tableau avec l'algorithme for_each et l'objet fonctionnel Affichefor_each(vecteurRat.begin(), vecteurRat.end(), Affiche());

● Affiche() : crée une instance de la classe Affiche qui est passée en paramètre à l'algorithme for_each ;

● for_each effectue l'appel Affiche(x) pour chaque élément x de la séquence.

Jean-Christophe Engel 99 janvier 2007

Page 100: Jean-Christophe Engel IFSIC - Université Rennes 1...IFSIC – Université Rennes 1 Programmation par objets en C++ Classes Implémentation rationnel.cc importer la définition de

IFSIC – Université Rennes 1 Programmation par objets en C++

Objet fonctionnel

Intérêt :

● objet fonctionnel = super fonction, avec attributs et état interne qu'on peut initialiser et qui peut changer

● chaque objet fonctionnel a un type qu'on peut passer comme paramètre d'un modèle de classe ou de fonction.

– typedef set<Rationnel, greater<Rationnel> > ensembleRationnel : greater<> est un objet fonctionnel (paramétré) passé en paramètre du conteneur set auquel il sert de critère de tri.

exemple : ajouter une valeur à tous les éléments d'un conteneur

● valeur connue à la compilation : une fonction suffitvoid ajouter10(int & element) { element += 10; }...vector<int> vnb;...for_each(vnb.begin(), vnb.end(), ajouter10);

Jean-Christophe Engel 100 janvier 2007

Page 101: Jean-Christophe Engel IFSIC - Université Rennes 1...IFSIC – Université Rennes 1 Programmation par objets en C++ Classes Implémentation rationnel.cc importer la définition de

IFSIC – Université Rennes 1 Programmation par objets en C++

Objet fonctionnel

exemple (suite)

● valeur connue à l'exécution ou différentes valeurs pour différentes situations ou valeur qui change à chaque appel : requiert un objet fonctionnel

– le constructeur initialise la valeur associée à l'objet fonctionnel

– l'appel utilise la valeur courante et peut éventuellement la modifierclass AjouterValeur {public : AjouterValeur(int init = defaut, int inc = 0) : valeur(init), increment(inc) { }; void operator () (int & element) { element += valeur; valeur += increment; };private: int valeur; const int increment; static const int defaut = 1;};

// ajouter 5 au premier élément, 6 au deuxième, ...for_each(vnb.begin(), vnb.end(), AjouterValeur(5, 1));...// ajouter à tous les éléments la valeur du premier élément du conteneurfor_each(vnb.begin(), vnb.end(), AjouterValeur(* vnb.begin()));

Jean-Christophe Engel 101 janvier 2007

Page 102: Jean-Christophe Engel IFSIC - Université Rennes 1...IFSIC – Université Rennes 1 Programmation par objets en C++ Classes Implémentation rationnel.cc importer la définition de

IFSIC – Université Rennes 1 Programmation par objets en C++

Objet fonctionnel

objets fonctionnels prédéfinis

● ce sont des modèles de classe paramétrés par un type : objet<type>()

expression effet

negate - unaire

plus, minus, multiplies, divides, modulus + , -, *, /, %

equal_to, not_equal_to ==, !=

less, greater, less_equal, greater_equal <, >, <=, >=

logical_not, logical_and, logical_or !, &&, ||

● less<T> est le prédicat par défaut pour les tris ou les comparaisons● #include <functional>

exemple : élever chaque élément d'un conteneur au carrétransform( cont.begin(), cont.end(), // 1ère séquence

cont.begin(), // 2ème séquencecont.begin(), // destinationmultiplies<Rationnel>()); // opération

Jean-Christophe Engel 102 janvier 2007

Page 103: Jean-Christophe Engel IFSIC - Université Rennes 1...IFSIC – Université Rennes 1 Programmation par objets en C++ Classes Implémentation rationnel.cc importer la définition de

IFSIC – Université Rennes 1 Programmation par objets en C++

Éléments des conteneurs

contraintes sur les éléments

un conteneur crée des copies internes des instances qu'on y place et renvoie des copies, d'où les contraintes :

● contraintes obligatoires

– posséder un constructeur de copie

– posséder un opérateur d'affectation(=)

– posséder un destructeur

● contraintes qui dépendent des situations

– posséder un constructeur par défaut (sans paramètre) : pour certaines méthodes des conteneurs séquentiels.

– posséder un opérateur d'égalité (==), par exemple pour les opérations de recherche

– posséder un opérateur d'infériorité (<) : c'est par défaut le critère de tri des conteneurs associatifs, appelé par l'objet fonctionnel less<>.

Jean-Christophe Engel 103 janvier 2007

Page 104: Jean-Christophe Engel IFSIC - Université Rennes 1...IFSIC – Université Rennes 1 Programmation par objets en C++ Classes Implémentation rationnel.cc importer la définition de

IFSIC – Université Rennes 1 Programmation par objets en C++

Éléments des conteneurs

sémantique par valeur

● Les conteneurs créent et renvoient des copies des éléments qu'on y ajoute : sémantique par valeur.

● autre approche : gérer des références (ou des pointeurs) sur les éléments : sémantique par référence

● atouts de la sémantique par valeur :

– simplicité

– la gestion par référence est source d'erreurs : il faut s'assurer que les références ne désignent pas des instances qui n'existent plus

● faiblesses

– la copie des éléments peut entraîner de mauvaises performances

– impossible de partager des éléments entre plusieurs conteneurs

● pour bénéficier de la sémantique par référence : créer des pointeurs intelligents (smart pointers) qui permettent de partager une instance entre plusieurs conteneurs et ne détruisent les instances que si elles ne sont plus référencées

Jean-Christophe Engel 104 janvier 2007

Page 105: Jean-Christophe Engel IFSIC - Université Rennes 1...IFSIC – Université Rennes 1 Programmation par objets en C++ Classes Implémentation rationnel.cc importer la définition de

IFSIC – Université Rennes 1 Programmation par objets en C++

Bibliographie

Le langage C++Bjarne Stroustrup

Addison-WesleyPearson Education

The C++ Standard LibraryNicolai Josuttis

Addison-WesleyPearson Education

Design patternsCatalogue de modèles de conceptionréutilisablesGamma, Helm, Johnson, Vlissides

Vuibert

Pour mieux développer avec C++Design patterns, STL, RTTI et smart pointersGéron, Tawbi

DUNOD

Jean-Christophe Engel 105 janvier 2007