145
Structures de données IFT-2000 Abder Alikacem Abder Alikacem Classes et objets en C++ Département d’informatique et de génie logiciel Édition Septembre 2009 Département d’informatique et de génie logiciel

Structures de données IFT-2000 Abder Alikacem Classes et objets en C++ Département d’informatique et de génie logiciel Édition Septembre 2009 Département

Embed Size (px)

Citation preview

Page 2: Structures de données IFT-2000 Abder Alikacem Classes et objets en C++ Département d’informatique et de génie logiciel Édition Septembre 2009 Département

Plan

Classes et objets Constructeur et destructeur Imbrication de classes Composition de classes Méthode et classe friend Méthodes statiques Méthodes optimisées Surcharge des opérateurs Le pointeur this Constructeur de copie et opérateur d’affectation Opérateur de portée :: Conversion de types Portée des identificateurs Membres mutables Traitement des exceptions

Page 3: Structures de données IFT-2000 Abder Alikacem Classes et objets en C++ Département d’informatique et de génie logiciel Édition Septembre 2009 Département

Les classes

Définition d’un nouveau type au sens C++ : ensemble de méthodes (fonctionnalités) auxquelles sont ajoutés des membres (données).

Les classes sont utilisées afin de fournir aux programmeurs les outils nécessaires pour concevoir des nouveaux types qui soient aussi faciles d'utilisation que les types de base. Ce sont des ensembles de:

données ayant un lien entre elles (comme struct en C)

« données membres » +

méthodes servant à manipuler les données membres « fonctions membres »

C’est la structure de base des langages orientés objet.

Page 4: Structures de données IFT-2000 Abder Alikacem Classes et objets en C++ Département d’informatique et de génie logiciel Édition Septembre 2009 Département

Les classes

Les classes sont comme les structures du langage C auxquelles on a ajouter des fonctionnalités supplémentaires. En particulier:

1. Tout comme les structures en C, les classes peuvent contenir des définitions de variables.

2. Les classe peuvent en plus contenir des définitions de fonctions.

3. Par défaut les membres (variables ou fonctions) d'une classe sont privés et inaccessibles au reste du programme. Pour rendre un membre accessible celui-ci doit explicitement être déclaré public.

Page 5: Structures de données IFT-2000 Abder Alikacem Classes et objets en C++ Département d’informatique et de génie logiciel Édition Septembre 2009 Département

Les classes

Une classe est une implémentation d’un type. Une variable de ce type (une instance de la classe) est appelée un objet.

Une classe est une structure d'objets, c'est-à-dire la déclaration de l'ensemble des entités qui composeront des objets.

Une classe peut être considérée comme un moule à partir duquel on peut

créer des objets.

Un objet est donc "issu" d'une classe. C'est une instanciation d'une classe,

c'est la raison pour laquelle on pourra parler indifféremment d'objet ou d'instance.

Page 6: Structures de données IFT-2000 Abder Alikacem Classes et objets en C++ Département d’informatique et de génie logiciel Édition Septembre 2009 Département

Les classes

La déclaration de la classe commence par le mot clef class et est encadrée par une paire d'accolades. L'accolade finale est suivie d'un point virgule. Les membres déclarés après le mot clef public forment l'interface de la classe. Ceux qui suivent le mot private sont invisibles de l'utilisateur. Par défaut, en l ‘absence de ces mots clés, les membres de la classe sont « privées ».

L'ordre de déclaration des méthodes et des attributs est laissé au libre arbitre du programmeur.

La déclaration des attributs est semblable à la déclaration d'une variable alors que celle d'une méthode ressemble à s'y méprendre au prototype d'une fonction ! Néanmoins, il ne faut pas oublier que chaque méthode possède un argument caché : l'objet sur lequel elle est invoquée.

Syntaxe de la définition d’une classe

class <class name> {<data + functions>} <vars> ;

Page 7: Structures de données IFT-2000 Abder Alikacem Classes et objets en C++ Département d’informatique et de génie logiciel Édition Septembre 2009 Département

Les classes

Une classe est composée de deux parties:

- Les attributs (parfois appelés données membres): il s'agit des données représentant l'état de l'objet.

- Les méthodes (parfois appelées fonctions membres): il s'agit des opérations applicables aux objets.

Généralement, les méthodes sont de quatre types :

les constructeurs (initialisation correcte) destructeur (fin de vie correcte) les accesseurs (lecture seulement) les modificateurs (lecture+écriture)

Page 8: Structures de données IFT-2000 Abder Alikacem Classes et objets en C++ Département d’informatique et de génie logiciel Édition Septembre 2009 Département

Les fonctions membres (méthodes)

Les fonctions membres peuvent être définies dans la classe même, dans un module séparé ou plus loin dans le code source. Dans ces cas, il suffit de préciser la classe pour laquelle la méthode déclarée doit être implémentée.

Syntaxe de la définition hors de la classe d'une méthode :

type Classe::nom_méthode( paramètres_formels )

{

// corps de la fonction

}

Si le code n’est pas trop long, les méthodes définies à l’intérieur de la classe (méthodes inline) peuvent avoir leur corps recopié à chaque appel pour accélérer l’exécution. Ce n’est pas le cas de celle définies à l’extérieur.

Page 9: Structures de données IFT-2000 Abder Alikacem Classes et objets en C++ Département d’informatique et de génie logiciel Édition Septembre 2009 Département

Les classes

Public, private, protected

Par défaut, dans une classe, seules les méthodes de cette classe peuvent accéder aux autres méthodes et aux membres. On dit que ceux-ci sont en accès private.

Pour être utilisable, une classe doit donc rendre publiques certaines méthodes. La spécification de public : (resp. private :) à l’intérieur de la classe change l’accès par défaut pour les membres et fonctions situés après cette déclaration. Plusieurs public : (resp. private :) peuvent apparaître dans une classe.

Troisième accès : protected, l’accès est autorisé aussi aux classes dérivées (nous verrons cela plus tard), mais pas pour les utilisations externes.

Page 10: Structures de données IFT-2000 Abder Alikacem Classes et objets en C++ Département d’informatique et de génie logiciel Édition Septembre 2009 Département

Les classes

Exemple d’une classe

class FigureGeometrique {public:

FigureGeometrique();~FigureGeometrique();inline double surface() const;inline const char *nom() const;void surface (double);

private:const char * nom;double surface;

}

constructeur

destructeur

accesseurs

modificateur

Page 11: Structures de données IFT-2000 Abder Alikacem Classes et objets en C++ Département d’informatique et de génie logiciel Édition Septembre 2009 Département

Les classes

Les fonctions « inline» doivent être définies dans le même fichier que celui dans lequel est déclarée la classe. Par défaut, toute fonction définie dans le corps dela classe est automatiquement « inline» (définition dans FigureGeometrique.h).

Les fonctions définies en dehors de la classe doivent être préfixées par <class name>:: Elles peuvent être définies dans un autre fichier que celui de la Classe (définition dans FigureGeometrique.cpp):

double FigureGeometrique::surface() const { return surface; }

const char * FigureGeometrique::nom() const { return nom; }

void FigureGeometrique::surface(double s) { surface= s; }

Exemple d’une classe…suite

Page 12: Structures de données IFT-2000 Abder Alikacem Classes et objets en C++ Département d’informatique et de génie logiciel Édition Septembre 2009 Département

Les classes

Exemple d’une classe…suite

Exemple de fonctions définies à l‘intérieur du contexte de la déclaration dans le fichier FigureGeometrique.h.

class FigureGeometrique {

public: FigureGeometrique(); ~ FigureGeometrique(); inline double surface() const { return surface; } inline const char * nom() const { return nom; } void surface(double s) { surface= s; }

private: const char *nom; double surface;

};

Page 13: Structures de données IFT-2000 Abder Alikacem Classes et objets en C++ Département d’informatique et de génie logiciel Édition Septembre 2009 Département

Les classes

Exemple d’une classe…suite

Les objets sont les instances de classes.

FigureGeometriqueX; // déclaration X.surface(2.0); // écriture double d = X.surface(); // lecture

cout << d << endl; // affichage

Page 14: Structures de données IFT-2000 Abder Alikacem Classes et objets en C++ Département d’informatique et de génie logiciel Édition Septembre 2009 Département

Les classes

Classe ou struct

Il existe une autre déclaration de classe : struct (accès public par défaut pour tous les membres et méthodes). class (accès privé par défaut pour tous les membres et méthodes).

class Point {// Deux membres, les coordonnées // du point, inaccessibles de l’extérieur (private)

int x, y;// Interface utilisateur, accessible de l’extérieurpublic:// Méthodes d’accès (en lecture) aux membres

int abscisse() { return x; }int ordonnee() { return y; }

// Méthodes de modification des membresvoid affect_x(int x) { x = x; }void affect_y(int y) { y = y; }

};

struct Point {// les coordonnées du point // sont accessibles de l’extérieur

int x, y;private:// Ce qui suit, jusqu’au prochain // "public:" n’est pas accessible

...};

Page 15: Structures de données IFT-2000 Abder Alikacem Classes et objets en C++ Département d’informatique et de génie logiciel Édition Septembre 2009 Département

Les classesNous allons reprendre ce concept et l’illustrer à l'aide de l'exemple des tableaux. Lorsque on passe un tableau en paramètre à une fonction, celle-

ci connaît l'adresse du début du tableau mais pas l'adresse de la fin. C'est pourquoi il est presque toujours nécessaire de fournir aussi la taille du

tableau.

Exemple:void copier(int *A, int n, int *B, int m){

int min = (n<m)?n:m;for (int i=0; i<min; i++)B[i]=A[i];

}int echanger(int *A, int n, int *B, int m){

if (n!=m) return 0;int* tmp=new int[n];copier(A, n, tmp, n);copier(B, m, A, n);copier(tmp, n, B, m);return 1;

}

Page 16: Structures de données IFT-2000 Abder Alikacem Classes et objets en C++ Département d’informatique et de génie logiciel Édition Septembre 2009 Département

Les classes

On doit donc fournir quatre paramètres alors qu'on ne veut réellement Passer que deux objets. Ce problème peut être résolu en définissant notre propre objet tableau qui inclue aussi sa taille: la classe Tableau.

class Tableau{

private: int nbelements; int *T;

public: Tableau(int); //constructeur~Tableau(); //destructeurint longueur() const; //accesseurint element(int) const; //accesseurvoid modifier (int, int); //modificateur

};

Page 17: Structures de données IFT-2000 Abder Alikacem Classes et objets en C++ Département d’informatique et de génie logiciel Édition Septembre 2009 Département

Les classes

Lors de l'implémentation des méthodes, il est donc nécessaire de préfixer le nom de la méthode implémentée du nom de la classe suivi de '::'. Par exemple, l'implémentation de la méthode element() de la classe Tableau se fait en spécifiant:

int Tableau::element(int i) const

Le constructeur est une méthode particulière qui porte le même nom que la classe et dont le but est d'initialiser les attributs lors de la création d'un objet.

Les méthodes element et longueur() sont déclarées constantes à l'aide du mot clef const. Cela signifie que leur code n'affecte en aucune manière la valeur des attributs de l'objet cible.

Page 18: Structures de données IFT-2000 Abder Alikacem Classes et objets en C++ Département d’informatique et de génie logiciel Édition Septembre 2009 Département

Méthodes constantes

Pour permettre au compilateur de mieux optimiser le code, le mot-clé const peut être ajouté à une méthode pour indiquer que celle-ci ne modifiera pas les membres de la classe. Celui-ci ndique qu'une méthode n'est pas intrusive.

class Point { int x, y;

public: // Interface utilisateur int abscisse() const { return x; } void affect_x(int x) { x = x; }

};

class Forme {…

double get_x () const;};

void foo(const Forme& f) {

f.get_x(); // OK}

Exemple 1

Exemple 2

Page 19: Structures de données IFT-2000 Abder Alikacem Classes et objets en C++ Département d’informatique et de génie logiciel Édition Septembre 2009 Département

Méthodes constantes

Exemple 3

class Date{public: ... int reqJour () const; int reqMois () const; int reqAnnee () const; ...};

int Date::reqJour () const{ return m_jour;}

Le compilateur fera la vérification que les attributs de l’objet ne seront pas modifiés dans cette méthode.

Le mot-clé const se retrouvedans l’interface et dans l’implantation

Page 20: Structures de données IFT-2000 Abder Alikacem Classes et objets en C++ Département d’informatique et de génie logiciel Édition Septembre 2009 Département

Méthodes constantes

Département d’informatique et de génie logiciel

20

class Date{public: void imprime();private: int m_jour; int m_mois; int m_annee;};

class Message{public: void imprime() const;private: string m_expediteur; Date m_dateRecu;};

void Message::imprime() const{ cout << m_expediteur << endl << m_dateRecu.imprime();}

void Date::imprime(){ cout << m_jour << ":" << m_mois << ":" << m_annee;}

Ne compile pas! le compilateur ne peut deviner que vous ne modifiez pas la date en l’imprimant...

Page 21: Structures de données IFT-2000 Abder Alikacem Classes et objets en C++ Département d’informatique et de génie logiciel Édition Septembre 2009 Département

Méthodes constantes

• Outil permettant d’améliorer la qualité du code de façon très importante

il force la classification.

• Il faut adhérer à cette façon de faire si on désire partager du code et utiliser des librairies qui ont adhéré à cette norme.

• La librairie standard adhère à cette norme.

Page 22: Structures de données IFT-2000 Abder Alikacem Classes et objets en C++ Département d’informatique et de génie logiciel Édition Septembre 2009 Département

Les classes

Tableau::Tableau(int n){

T=new int[n];nbelements=n;

}

Tableau::~Tableau(){

delete[] T;}

int Tableau::longueur() const{

return nbelements;}

int Tableau::element(int i) const{

return T[i];}

void Tableau::modifier(int i, int a){

T[i]=a;}

Implémentation des fonctions membres (méthodes) de la classe Tableau

Page 23: Structures de données IFT-2000 Abder Alikacem Classes et objets en C++ Département d’informatique et de génie logiciel Édition Septembre 2009 Département

Les classes

On peut utiliser la classe Tableau de la façon suivante:

void copier(Tableau& A, Tableau& B){

int min=(A.longueur()<B.longueur()) ? A.longueur():B.longueur();for (int i=0; i<min; i++)B.modifier(i,A.element(i));

}

int echanger(Tableau &A, Tableau &B){

if (A.longueur() != B.longueur()) return 0;;Tableau tmp(A.longueur());copier(A, tmp);copier(B, A);copier(tmp, B);

return 1;}

Page 24: Structures de données IFT-2000 Abder Alikacem Classes et objets en C++ Département d’informatique et de génie logiciel Édition Septembre 2009 Département

Les classes

Dans la fonction echanger, la variable tmp est créée en appelant le constructeur

avec le paramètre A.longueur(). Cela nous assure que tmp est un tableau de

même taille que A.

Seuls les membres dont la déclaration apparaît après le mot clef public peuvent

être utilisés ailleurs dans le programme.

Les variables nbelements et T ne sont accessibles que par les fonctions membres (privées ou publiques) de la classe Tableau. Par conséquent, le code suivant est illégale:

Tableau t(10); // tableau de 10 élémentsint n=t.nbelements; // instruction illégale

Page 25: Structures de données IFT-2000 Abder Alikacem Classes et objets en C++ Département d’informatique et de génie logiciel Édition Septembre 2009 Département

Instanciation d’une classe

D’une manière générale, comme pour struct , le nom de la classe représente un nouveau type de donnée.

On peut donc définir des variables, de ce nouveau type; (créer des objets ou des instances) :

Tableau t1; // une instance simple (statique)

Tableau *t2; // un pointeur (non initialisé)

t2 = new Tableau(10); // création (dynamique) d'une instance

Page 26: Structures de données IFT-2000 Abder Alikacem Classes et objets en C++ Département d’informatique et de génie logiciel Édition Septembre 2009 Département

Les objets

Ce sont des instances d’une classe, et de la même manière qu'une classe, un objet est caractérisé par:

Ses attributs: Il s'agit des données caractérisant l'objet. Ce sont des variables stockant des informations d'état de l'objet

Ses Méthodes (appelées parfois fonctions membres): Les méthodes d'un objet caractérisent son comportement, c'est-à-dire l'ensemble des actions (appelées opérations) que l'objet est à même de réaliser. Ces opérations permettent de faire réagir l'objet aux sollicitations extérieures (ou d'agir sur les autres objets). De plus, les opérations sont étroitement liées aux attributs, car leurs actions peuvent dépendre des valeurs des attributs, ou bien les modifier

De plus, un objet a aussi une Identitée.

Page 27: Structures de données IFT-2000 Abder Alikacem Classes et objets en C++ Département d’informatique et de génie logiciel Édition Septembre 2009 Département

Utilisation d’un objet

Après avoir créé une instance, un objet de façon statique ou dynamique, on peut accéder aux attributs et méthodes de la classe.

Cet accès se fait comme pour les structures à l'aide de l'opérateur . ou ->.

cout << t1.longeur() << endl;

cout << t2->element(0) << endl;

Page 28: Structures de données IFT-2000 Abder Alikacem Classes et objets en C++ Département d’informatique et de génie logiciel Édition Septembre 2009 Département

Constructeur

On observe que la fonction membre Tableau(int) ne retourne aucune valeur et

qu'elle possède le même nom que la classe dont elle est membre. Une telle

fonction est appelée constructeur, il est utilisés à la déclaration de l’objet

pour le construire (affecter les membres, allouer la mémoire, etc.) à partir de

différents paramètres.

Les constructeur sont utilisés afin d'initialiser les objets lors de leur création.

Si aucun constructeur n'est présent dans la définition d'une classe alors un

constructeur par défaut est utilisé. Celui-ci ne fait qu'allouer l'espace nécessaire pour représenter les instances de la classe concernée.

Page 29: Structures de données IFT-2000 Abder Alikacem Classes et objets en C++ Département d’informatique et de génie logiciel Édition Septembre 2009 Département

Constructeur

- On peut avoir plusieurs constructeur pour une classe- Tous portent le même nom que la classe - n ‘ont pas de type de retour - sont invoqués implicitement lors de la création d‘un objet déclaration d‘une variable

variable temporaire (compilateur) usage de new ou new []

- diffèrent par leur signature(forcément :-)

class X {

public : X();…

};

Page 30: Structures de données IFT-2000 Abder Alikacem Classes et objets en C++ Département d’informatique et de génie logiciel Édition Septembre 2009 Département

Constructeur

Si le programmeur ne veut pas de constructeurs, le compilateur le fait automatiquement pour lui, cependant, il faut les spécifier à vide lors de la déclaration de la classe.

class X { public: X() {}

X(const X&) {} X& operator=(const X&) {}

} ;

Page 31: Structures de données IFT-2000 Abder Alikacem Classes et objets en C++ Département d’informatique et de génie logiciel Édition Septembre 2009 Département

Constructeur

Il peut donc y avoir plusieurs constructeurs.

class X {public: X()

X(const X&);

X& operator = (const X&);

};

Constructeur par défaut

Constructeur de copie

Surcharge de =X a; //défautX b = a; // copieX c(a); //copieX d = X(a); //double copied = a //affectation

Page 32: Structures de données IFT-2000 Abder Alikacem Classes et objets en C++ Département d’informatique et de génie logiciel Édition Septembre 2009 Département

Constructeur

Pourquoi 3 constructeurs ?

Défaut = initialisation(*)Copie = recopie à partie d’un modèleAffectation = doit aussi traite le cas « X = X; »

Notation fonctionnelle à la « constructeur de copie »

int i(0) est équivalent à int i = 0;i(2) i = 2;

(*) Utile lors des appels de fonctions (un objet peut être en argument), pour le retour d’une fonction (un objet peut être retournée) et lors d’instanciationD’un objet à partir d’un autre :

X x1();X x2(x1);

Page 33: Structures de données IFT-2000 Abder Alikacem Classes et objets en C++ Département d’informatique et de génie logiciel Édition Septembre 2009 Département

Constructeur

class Point { int x, y;public:

Point() : x(0), y(0) { } Point(int x, int y) : x(x), y(y) { } Point(const Point& P) : x(P.x), y(P.y) { } int abscisse() { return x; } int ordonnee() ;

};

Point X; // appel du constructeur videPoint M(3,4); // appel du constructeur sur les entiersPoint P(M); // appel du constructeur de recopie physique

Exemple 1

Page 34: Structures de données IFT-2000 Abder Alikacem Classes et objets en C++ Département d’informatique et de génie logiciel Édition Septembre 2009 Département

Constructeur

Exemple 2

class Date{public: Date(); Date(int jour, int mois, int annee); Date(const std::string& txtDate);};

Date e;Date d(31,3,1997);Date f("31 mars 1997");Date g(31, "mars", 1997);Date vDate[10];

Constructeurs dans l’ordre

Date(int,string,int);n’existe pas!

Date() appelé 10 fois

Page 35: Structures de données IFT-2000 Abder Alikacem Classes et objets en C++ Département d’informatique et de génie logiciel Édition Septembre 2009 Département

Construction des sous-objets

• Utilisez une liste d’initialisation: construire tous les sous-objets avant le corps du constructeur parce que lorsqu'on y est rendu, ces objets sont déjà construit, i.e. on a déjà appelé leur constructeur par défaut.

Date::Date(int jour, int mois, int annee){ // Les attributs ont déjà été initialisés par défaut. m_jour = jour; m_mois = mois; m_annee = annee;}

// Version préférableDate::Date(int jour, int mois, int annee): m_jour(jour), m_mois(mois), m_annee(annee){}

Liste d'initialisation

Page 36: Structures de données IFT-2000 Abder Alikacem Classes et objets en C++ Département d’informatique et de génie logiciel Édition Septembre 2009 Département

Construction des sous-objets

Construire un objet avec des valeurs par défaut pour ensuite les changer avec les valeurs désirées.

Un appel de plus est fait inutilement.

Message::Message(const string& expediteur, const string& destinataire,

const Date& dateRecu, const string& titre,

const string& message): m_expediteur(expediteur), m_destinataire(destinataire), m_dateRecu(dateRecu), m_titre(titre), m_message(message){}

Exemple 2 :

Page 37: Structures de données IFT-2000 Abder Alikacem Classes et objets en C++ Département d’informatique et de génie logiciel Édition Septembre 2009 Département

Destructeur

La fonction membre ~Tableau() est appelée destructeur, elle est appelé

automatiquement quand l’objet ne sera plus utilisé (fermeture d’accolade }).

Au retour de la fonction echanger, la variable locale tmp sera éliminée par le

destructeur et l'espace qu'elle utilise sera libéré. Si aucun destructeur n‘était

défini alors le destructeur par défaut serait utilisé et seuls tmp.T et tmp.nbelements seraient éliminés. Le tableau créé par le constructeur

serait conservé mais inaccessible jusqu‘à la fin de l'exécution du programme, ce

qui résulterait en une perte d'espace inacceptable.

Page 38: Structures de données IFT-2000 Abder Alikacem Classes et objets en C++ Département d’informatique et de génie logiciel Édition Septembre 2009 Département

Destructeur

- porte le même nom que la classe avec ~- n ‘a pas de type de retour - sont invoqués lors de la destruction d‘un objet fin de portée de la déclaration d‘une variable

fin de la variable temporaire (compilateur) usage de delete ou delete []

- n’a jamais d’argument, il n’y en as donc qu’un- est utile lorsque l’objet est responsable de ressources allouées dynamiquement.

class X {

public : ~X();…

};

Page 39: Structures de données IFT-2000 Abder Alikacem Classes et objets en C++ Département d’informatique et de génie logiciel Édition Septembre 2009 Département

Destructeur

Si le programmeur ne définit pas le destructeur, le compilateur le fait automatiquement pour lui, cependant, et comme les constructeurs, il faut le spécifier à « vide » lors de la déclaration de la classe.

class X { public:

~X() {} …

} ;

Il est inutile s'il n'y a pas de désallocation de ressource.

Page 40: Structures de données IFT-2000 Abder Alikacem Classes et objets en C++ Département d’informatique et de génie logiciel Édition Septembre 2009 Département

Destructeur

class Tableau {int * d;

public:Tableau(int s = 10) { d = new int[s]; }~Tableau() { delete [] d; }

};

{ Tableau t; // ici de taille 10 par défaut ...} // Appel de tous les destructeurs des objets déclarés dans ce groupe

Exemple

Page 41: Structures de données IFT-2000 Abder Alikacem Classes et objets en C++ Département d’informatique et de génie logiciel Édition Septembre 2009 Département

Constructeur / Destructeur

class Date{public: Date(int j, int m, int a); ~Date();private: int m_jour; int m_mois; int m_annee;};Date::Date(int j, int m, int a): m_jour(j), m_mois(m), m_annee(a){}Date::~Date(){}

void main(){ Date d(1, 1, 1965);}

Date déclaréeConstructeur appelé

Sortie du «scope»,destructeur appelé

Initialisation seulement

Rien à faire? => inutile d’implanter

Page 42: Structures de données IFT-2000 Abder Alikacem Classes et objets en C++ Département d’informatique et de génie logiciel Édition Septembre 2009 Département

Constructeur / Destructeur

class string{public: string(const char* strP); ~string();private: char *m_strP;};string::string (const char* strP){ m_strP = new char[strlen(strP)+1]; strcpy (m_strP, strP);}string::~string(){ delete [] m_strP;}

void main(){ string s("Bonjour");}

string déclarée,constructeur appelé

Sortie du «scope»,destructeur appelé

Initialisation et allocation de ressources.

Désallocation de ressources

Page 43: Structures de données IFT-2000 Abder Alikacem Classes et objets en C++ Département d’informatique et de génie logiciel Édition Septembre 2009 Département

Constructeur et destructeur

Les données membres d'une classe doivent être initialisées par uneméthode d'initialisation.

De même, après avoir fini d'utiliser un objet, il est bon de prévoir une méthode permettant de détruire l'objet (en libérant par exemple la mémoire).

Le constructeur est une méthode qui porte le même nom que la classe. C’est dans le constructeur que les attributs d’un objet sont initialisées lors de sa création.

Un constructeur ne peut pas spécifier de valeur ou type de retour.

Le constructeur d’une classe est éxécuté automatiquement à chaque fois qu’une instance de la classe est crée. Que se passe t ’il si l’instance est passée par valeur comme paramètre à une fonction?

Une classe peut avoir ou non un constructeur par défaut. Il s’agit d’un constructeur sans aucun paramètre.

Page 44: Structures de données IFT-2000 Abder Alikacem Classes et objets en C++ Département d’informatique et de génie logiciel Édition Septembre 2009 Département

Constructeur et destructeur

Si aucun constructeur n’a été défini dans la classe, C++ en crée un automatiquement. C’est un constructeur par défaut, et il ne fait rien. Une classe a donc toujours un constructeur, mais pas forcément un constructeur par défaut ; en effet, si on ne définit que des constructeurs qui prennent des paramètres, C++ ne fournit pas le constructeur par défaut automatiquement.

De la même façon que pour les constructeurs, le destructeur est une fonction membre spécifique de la classe qui est appelée implicitement à la destruction de l'objet. Ce destructeur est une fonction qui porte comme nom, le nom de la classe précédé du caractère ~(tilda) , qui ne retourne pas de valeur (pas même un void) et qui n'accepte aucun paramètre (le destructeur ne peut donc pas être surchargé).

Page 45: Structures de données IFT-2000 Abder Alikacem Classes et objets en C++ Département d’informatique et de génie logiciel Édition Septembre 2009 Département

Constructeur

Le constructeur est donc une fonction membre spécifique de la classe qui est appelée implicitement à l'instanciation de l'objet.

class Cercle {private: int x, y; int rayon;public : Cercle(int, int=0, int=0); // constructeur

};

Cercle::Cercle(int r, int cx, int cy) { rayon = r; x = cx; y = cy; }

Cercle ballon(20,10,10);

Lorsqu’un constructeur par défaut n’existe pas, on ne peut déclarer une instance de classe sans préciser de paramètres. Par exemple, pour l’exemple suivant,

class Autre { private: double d; public: Autre(double dd) { d = dd; }}

l’appel: Autre a; est illégal.

Page 46: Structures de données IFT-2000 Abder Alikacem Classes et objets en C++ Département d’informatique et de génie logiciel Édition Septembre 2009 Département

Constructeur

Si on veut créer un tableau d’instances de la classe sans donner de valeurs initiales, il faut définir un constructeur par défaut. Il est alors appelé pour tous les éléments du tableau :

Avion A[10]; //10 appels du constructeur par défaut de Avion

Important: bien que les constructeurs aussi peuvent avoir des arguments par défaut comme toute autre fonction:

class Autre { private: double d; public: Autre(double dd = 0){ d = dd;}};

Autre a; // ok Autre tab[3]; //NON, car pas de constructeur par défaut

Page 47: Structures de données IFT-2000 Abder Alikacem Classes et objets en C++ Département d’informatique et de génie logiciel Édition Septembre 2009 Département

Constructeur

Un constructeur ne peut pas être appelé autrement que lors d’une initialisation. Cependant, il peut l’être de différentes façons. Par exemple, s’il existe un constructeur qui n’admet qu’un seul paramètre, ou plusieurs mais tel que tous les arguments sauf le premier ont une valeur par défaut, on peut l’appeler en écrivant le signe égal suivi du paramètre:

Autre au = 1.2; // appel de Autre::Autre(1.2)

Cette écriture est équivalente à la forme classique : Autre au(1.2);

En outre, il est possible d’initialiser des tableaux de cette façon :Autre atab[4] = { 1.2, 2, 0.7, -9.9 };

Par contre, dans ce cas, il faut absolument préciser toutes les valeurs initiales parce que il n'y a pas de constructeur par défaut dans notre implémentation de la classe Autre.

Page 48: Structures de données IFT-2000 Abder Alikacem Classes et objets en C++ Département d’informatique et de génie logiciel Édition Septembre 2009 Département

Constructeur

Il est parfaitement possible de préciser une valeur par défaut à un argument de type classe, pourvu qu’on utilise un constructeur :

void f(exemple ex = exemple() );void f2(exemple ex = exemple(1, 1) );void g(Autre au = 0);

Dans le dernier cas, on a encore utilisé le changement de type automatique.

Page 49: Structures de données IFT-2000 Abder Alikacem Classes et objets en C++ Département d’informatique et de génie logiciel Édition Septembre 2009 Département

Destructeur

Le destructeur est donc une méthode particulière qui porte le même nom que la classe précédé du symbol ‘~’. Le destructeur est la dernière méthode appelée par une instance lorque le bloc de code dans laquelle celle ci évoluait a terminé son exécution.

Le destructeur est aussi appelé lors d ’un appel d ’opérateur delete sur l ’instance.

C’est dans le destructeur que la mémoire qui avait été allouée à la construction et pendant la vie de l ’instance est rendue au système.

Que se passe t ’il si deux blocs mémoires sont partagé par deux instances de la même classe?

Page 50: Structures de données IFT-2000 Abder Alikacem Classes et objets en C++ Département d’informatique et de génie logiciel Édition Septembre 2009 Département

Destructeur

Un destructeur n’a aucun résultat, comme les constructeurs, et n’admet aucun argument ; de ce fait, il ne peut y avoir qu’un destructeur par classe.

D’une façon générale, le destructeur doit tout « remettre en ordre dans ce que l’instance de classe peut avoir modifié. Outre la libération de la mémoire prise, il peut aussi avoir à fermer des fichiers ouverts, à détruire des éléments provisoires, etc.

Le destructeur standard (fournit par défaut) ne fait rien.

Page 51: Structures de données IFT-2000 Abder Alikacem Classes et objets en C++ Département d’informatique et de génie logiciel Édition Septembre 2009 Département

new et delete avec constructeurs et destructeurs

Un appel à l ’opérateur new (création d ’une instance de manière dynamique) provoquera un appel de constructeur.

Autre* C = new Autre(...);

class show{private: int a;public: show(int);

int get_a(){return a;}};

show::show(int i){a = i;

cout<< "Appel du constructeur: show(int i)";}

int foo(show a){ cout<<"Dans foo"<<endl; return a.get_a();}

int main(){foo(1);return 1;}//foo(show(1));serait également légale

Dans ces cas les constructeurs adéquats sont appelés à l’entrée de la fonction (et les destructeurs à la sortie).

Page 52: Structures de données IFT-2000 Abder Alikacem Classes et objets en C++ Département d’informatique et de génie logiciel Édition Septembre 2009 Département

L’opérateur new réserve donc la place mémoire nécessaire à l’objet dans le heap ; il appelle aussi un constructeur. Inversement, delete appelle d’abord le destructeur, puis libère la place mémoire.

Comme une classe peut avoir plusieurs constructeurs, on peut préciser quel constructeur est appelé au moment de l’appel de new. Il suffit pour cela d’écrire la liste des arguments derrière le nom de classe qui suit new.

exemple *pe1 = new exemple(1, 2); // appel du constructeur 2exemple *pe2 = new exemple; // appel du constructeur 1classexmpl *c2 = new classexmpl(*c1); // constructeur de copie

new et delete avec constructeurs et destructeurs

Page 53: Structures de données IFT-2000 Abder Alikacem Classes et objets en C++ Département d’informatique et de génie logiciel Édition Septembre 2009 Département

Lorsqu’aucun paramètre n’est précisé le constructeur par défaut est appelé ; s’il n’existe pas, une erreur de compilation se produit.

Il est possible de créer un tableau avec new, mais dans ce cas c’est le constructeur par défaut qui est obligatoirement appelé ; il n’y a pas de moyen d’en préciser un autre (contrairement aux tableaux statiques qui peuvent être initialisés par un constructeur à argument unique).

Pour ce qui est de l’instruction delete, il n’y a pas le choix : chaque classe ayant un seul destructeur (possiblement implicite), c’est celui-là qui est appelé avant de supprimer la place mémoire.

new et delete avec constructeurs et destructeurs

Page 54: Structures de données IFT-2000 Abder Alikacem Classes et objets en C++ Département d’informatique et de génie logiciel Édition Septembre 2009 Département

Problème particulier aux tableaux:

exemple *pex = new exemple[10];...delete pex; // incorrect

Le compilateur, qui n’a aucun moyen de connaître la taille du tableau pointé par pex, n’appellera le destructeur que pour le premier élément, ce qui peut poser problème. Pour lui demander de tout détruire, il faut préciser explicitement avec delete, le nombre d’éléments à supprimer :

exemple *pex = new exemple[10];...delete[10] pex;

Il faut se rappeler de ceci dans la déclaration du destructeur.

new et delete avec constructeurs et destructeurs

Page 55: Structures de données IFT-2000 Abder Alikacem Classes et objets en C++ Département d’informatique et de génie logiciel Édition Septembre 2009 Département

Ordre d’appel des constructeurs et destructeur

Les constructeurs des données membres sont appelés avant le constructeur De la classe qui les englobe et dans l ‘ordre de déclaration des données.

Les destructeurs des données membres sont appelés après le destructeur de la classe qui les englobe et dans l ‘ordre inverse de déclaration des données.

class X{public :

X() { cout << ‘x’;}~X() {cout << ‘X’;}class Y y;class Z z;

};

class Y{public :

Y() { cout << ‘y’;}~Y() {cout << ‘Y’;}

};

class Z{public :

Z() { cout << ‘z’;}~Z() {cout << ‘Z’;}

};

int main(){

X x;cout << endl;return 0;

};

Page 56: Structures de données IFT-2000 Abder Alikacem Classes et objets en C++ Département d’informatique et de génie logiciel Édition Septembre 2009 Département

Imbrication de classes

class X { public: X();

private: class Y {...}; ...

};

On peut déclarer une classe dans le corps d’une autre classe

Page 57: Structures de données IFT-2000 Abder Alikacem Classes et objets en C++ Département d’informatique et de génie logiciel Édition Septembre 2009 Département

Composition de classes

class Y {...}; class X {

public: X(); …

private: Y y; ...

};

Les données membres d’une classe peuvent être des objets, c’est-à-diredes instances d’une autre classe. On parle alors de composition ou agrégation de classes

Page 58: Structures de données IFT-2000 Abder Alikacem Classes et objets en C++ Département d’informatique et de génie logiciel Édition Septembre 2009 Département

Ce que l’on pourrait prendre pour une méthode déclarée friend est en fait une fonction classique : ce n’est absolument pas une méthode de la classe!

Le mot clef friend permet simplement d’indiquer à la classe que cette fonction pourra accéder à toutes les données privées (membres ou méthodes). L’ambiguïté vient du fait que cette indication passe pour une déclaration.

class Point {int x, y;

public:friend void affiche(const Point& M) { cout << M.x << <<M.y;

}void affiche_interne() {cout << x << << y; }

};...

Point M(3,4);affiche( M ) ; // affiche est une fonction globale classiqueM.affiche_interne(); // affiche_interne est une méthode

Méthode friend

Page 59: Structures de données IFT-2000 Abder Alikacem Classes et objets en C++ Département d’informatique et de génie logiciel Édition Septembre 2009 Département

De même, une classe peut être indiquée friend à l’intérieur d’une autre classe. Là encore cela ressemble à une déclaration précédée du mot-clé friend. Ainsi les méthodes de cette classe (implémentées ultérieurement) pourront manipuler les données privées de la classe dont elle est «amie».

Classe friend

class B{ public: B() {a = new A();};

~B() {};

private:A *a; void reinit_a() {

a->i = 0; a->f= 0.0;

}; };

class A{ public: friend class B;

A() {i = 0; f = 0.0;}; ~A() {};

private:int i;float f;

};

Page 60: Structures de données IFT-2000 Abder Alikacem Classes et objets en C++ Département d’informatique et de génie logiciel Édition Septembre 2009 Département

Fonctions membres statiques

• Méthode de classe ne nécessitant pas la présence d'un objet pour le traitement

• méthode statique.

• Comme une fonction mais associée à la classe.• Ne touche pas aux attributs de la classe, à moins que ceux-ci

ne soient aussi statiques (attribut commun à tous les objets de la classe).

Page 61: Structures de données IFT-2000 Abder Alikacem Classes et objets en C++ Département d’informatique et de génie logiciel Édition Septembre 2009 Département

Fonctions membres statiques

Le mot-clé static permet donc de définir des membres ou des méthodes «globales».

class A {friend class B;

public: A() { i =0; f = 0.0; n++;};~A() {};static int n;

private :int i;float f;

}

Sorte de variable globale « locale à la classe »initialisée à 0 par le compilateur si pas initialisée par le programmeur

int A:: n =-1;

Page 62: Structures de données IFT-2000 Abder Alikacem Classes et objets en C++ Département d’informatique et de génie logiciel Édition Septembre 2009 Département

Fonctions membres statiques

class A {friend class B;

public: A() { i =0; f = 0.0; n++;};~A() {};static void reset() { n = 0;}

private:int i;float f;static int n;

};

Fonction/méthode «de classe » qui seulepeut modifier les donnéesmembres statiques

A:: reset();

Un membre static est identique pour toutes les instances de la classe. Toute modification par un objet est reconnue par tous les

autres objets.

• N'a pas besoin d'un objet du type de la classe pour être appelée.

• Norme :Toujours appeler les méthodes

statiques avec le «scope» de la classe et ce, même si vous avez un objet de ce type entre les mains.

Page 63: Structures de données IFT-2000 Abder Alikacem Classes et objets en C++ Département d’informatique et de génie logiciel Édition Septembre 2009 Département

Fonctions membres statiques

Une méthode est normalement appelée au travers d’un objet. Une méthode static est appelée par la classe (pour manipuler les membres static).

class Repere {static Point origine;

public:Repere() {};static void changement_origine(const Point& P) { origine = P; }Point _origine() { return origine; }

};Point Repere:: origine(0,0);int main() {

Repere R1, R2;Point M(3,4);Repere::changement_origine( M );cout << "Abscisse de l’origine" <<(R2._origine()).abscisse() << endl;return 0;

}

Page 64: Structures de données IFT-2000 Abder Alikacem Classes et objets en C++ Département d’informatique et de génie logiciel Édition Septembre 2009 Département

Fonctions membres statiques

--- INTERFACE ---class Date{public: void asgDate (int jour, int mois, int annee); static bool valideDate (int jour, int mois, int annee); static bool estBissextile (int annee);private: …};

--- IMPLÉMENTATION ---int Date::jourParMois[12] ={31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};

bool Date::valideDate(int jour, int mois, int annee){ return jour > 0 && mois > 0 && mois <= 12 && ((mois == 2 && jour == 29 && Date::estBissextile(annee)) || (j < jourParMois[mois - 1]));}bool Date::estBissextile(int annee){ return (((annee % 4 == 0) && (annee % 100 != 0)) || ((annee % 4 == 0) && (annee % 100 == 0) && (annee % 400 == 0)) );}

Pas de const pour une méthode statique

La méthode peut être déclarée Statique puisqueaucun attributnon statiquen'est utilisé

Exemple 1

Page 65: Structures de données IFT-2000 Abder Alikacem Classes et objets en C++ Département d’informatique et de génie logiciel Édition Septembre 2009 Département

Fonctions membres statiques

Exemple 2

Département d’informatique et de génie logiciel

65

class Etudiant{public: Etudiant () {m_nbInstances++;} ~Etudiant () {m_nbInstances--;} static int reqNbInstances () {return m_nbInstances;}private: static int m_nbInstances;};

int Etudiant::m_nbInstances=0;void main(){ { Etudiant et1, et2, et3; cout << "Résultat :" << endl; cout << Etudiant::reqNbInstances() << endl; Etudiant et4, et5; cout << Etudiant::reqNbInstances() << endl; } cout << Etudiant::reqNbInstances() << endl;}

On peut utiliser un attributstatique dans un objet

Une méthode statique ne peutqu'utiliser des attributsstatiques.

Résultat:350

Attribut commun à tous les objets de la classe

On sort du "scope": appel au destructeur

Page 66: Structures de données IFT-2000 Abder Alikacem Classes et objets en C++ Département d’informatique et de génie logiciel Édition Septembre 2009 Département

Fonctions membres statiques

Grâce aux fonctions et aux données statiques, écrire une classe qui compte en permanence le nombre d’objets « actifs », le nombre d’objets « créés » et le nombre d’objets détruits. Ajoutez une fonction d’affichage de ces trois nombres par redéfinition de l’opérateur de sortie sur un flot.

Exercice

Page 67: Structures de données IFT-2000 Abder Alikacem Classes et objets en C++ Département d’informatique et de génie logiciel Édition Septembre 2009 Département

Méthodes optimisées

• Solution en C++ pour les méthodes simples:les déclarer inline.

• = Le compilateur élimine l’appel de fonction en le remplaçant par un accès direct à la donnée.

• Le code de la méthode doit être très simple et ne pas avoir d’effet de bord.

• Les méthodes inline font croître rapidement la dimension du code exécutable...

Page 68: Structures de données IFT-2000 Abder Alikacem Classes et objets en C++ Département d’informatique et de génie logiciel Édition Septembre 2009 Département

Méthodes optimisées

class Date{public: void asgDate(int jour,int mois,int annee); int reqMois() const;};

inline int Date::reqMois() const{ return m_mois;}

#include "Date.h"void Date::asgDate(int jour, int mois, int annee){ m_jour = jour; m_mois = mois; m_annee = annee;}

Date.h

Date.cpp

Méthode inline

Méthode non inline

Page 69: Structures de données IFT-2000 Abder Alikacem Classes et objets en C++ Département d’informatique et de génie logiciel Édition Septembre 2009 Département

Fonctions inline ou macro?

Département d’informatique et de génie logiciel

69

• Les programmeurs en C font souvent usage du préprocesseur avec #define pour implanter un fonction inline :

#define carre(x) (x)*(x);int x = 5;int y = carre(++x);

inline int carre(int x) {return x*x;}int x = 5;int y = carre(++x);

Résultat : 49 !??!

Résultat : 36.

Page 70: Structures de données IFT-2000 Abder Alikacem Classes et objets en C++ Département d’informatique et de génie logiciel Édition Septembre 2009 Département

Méthodes optimisées

• L'usage de remplacement de symboles avec #define est source d'erreur,

notamment pour les fonctions mathématiques.En C++, utiliser les fonctions ou les méthodes inline à la

place.• Les méthodes inline

• assurent la protection des données (encapsulation)• assurent la validation de type d'une fonction régulière. • améliorent la performance en évitant les appels de fonction.

Page 71: Structures de données IFT-2000 Abder Alikacem Classes et objets en C++ Département d’informatique et de génie logiciel Édition Septembre 2009 Département

Opérateurs

Un opérateur est une fonction ou une méthode avec un appel particulier.

class Complexe { float re, im;

public:// une méthode peut être un opérateur ...Complexe& operator+= (Complexe x) {

re += x.re;im += x.im;return *this;

}};

// ... tout comme une fonction classiqueComplexe operator+ (Complexe x, Complexe y) {

Complexe r = x;return r += y;

}

void f(Complexe x, Complexe y, Complexe z) {Complexe r1 = x + y + z; // r1 = operator+(x, operator+(y,z) )Complexe r2 = x;r2 += y; // r2.operator+=( y )r2 += z; // r2.operator+=( z )

}

Page 72: Structures de données IFT-2000 Abder Alikacem Classes et objets en C++ Département d’informatique et de génie logiciel Édition Septembre 2009 Département

Surcharge des opérateurs

Il est plus intuitif et plus clair d'additionner par exemple deux matrices en surchargeant l'opérateur d'addition et en écrivant :

result = m0 + m1;

que d'écrire : matrice_add(result, m0, m1);

La plupart des opérateurs sont surchargeables. Il faut veiller à respecter l'esprit de l'opérateur.

Lorsque l'on surcharge un opérateur, il n'est pas possible de : changer sa priorité changer son associativité changer sa pluralité (unaire, binaire, ternaire) créer de nouveaux opérateurs

Page 73: Structures de données IFT-2000 Abder Alikacem Classes et objets en C++ Département d’informatique et de génie logiciel Édition Septembre 2009 Département

Surcharge des opérateurs

L'opérateur = est le seul à être prédéfini pour toutes les classes:

a=b;

Par défaut, il affecte aux variables de champs de l'objet a les valeurs des variables de b. Il est important de le surcharger dans certains cas.

Il est possible de surcharger tous les opérateurs, sauf:

. (sélection de membre) :: (résolutionde nom) .* ?: sizeof

Les opérateurs suivant peuvent tous être redéfinis:

() [] -> + - ++ -- ! ~ * & new new[] delete * / % + - << >> < <= > >= == != & ^ || && | = += -= *= = ,

Page 74: Structures de données IFT-2000 Abder Alikacem Classes et objets en C++ Département d’informatique et de génie logiciel Édition Septembre 2009 Département

Surcharge des opérateurs

On ne peut changer

les règles de précédencel’associativitéle nombre d’opérandes

On ne peut créer de nouveaux opérateurs: |x| i.e. valeur absolue

y := x i.e. assignation à la Pascaly = x**2 i.e. x à la puissance 2.

Pour surcharger un opérateur, la syntaxe est la suivante:

<resultat> operator<type d'operateur>(<arguments>) {...}

Page 75: Structures de données IFT-2000 Abder Alikacem Classes et objets en C++ Département d’informatique et de génie logiciel Édition Septembre 2009 Département

Surcharge des opérateurs

Exemple 1. Opérateur ()

L’opérateur parenthèses permet de donner un type à une fonction (de définir une fonction de classe). Ainsi les fonctions peuvent être manipulées plus facilement (comme des objets).

class Incrementeur { int inc;

public: Incrementeur(int i) : inc(i) {} int operator() (int i) { return i+inc; }

};

int main() {Incrementeur plus_un(1), plus_deux(2); // Appel du constructeurint a = plus_deux(3); // a <-- 5, par l’appel de la méthode ()

}

Page 76: Structures de données IFT-2000 Abder Alikacem Classes et objets en C++ Département d’informatique et de génie logiciel Édition Septembre 2009 Département

Surcharge des opérateurs

class point {private : float abscisse, ordonnee;public : point();

point(float,float);void afficher ();point operator + (point);float operator * (point);

};

point point::operator +(point p){point resultat;resultat.abscisse = abscisse + p.abscisse;resultat.ordonnee = ordonnee + p.ordonnee;return resultat;

}

float point::operator *(point p){return (abscisse * p.abscisse + ordonnee *

p.ordonnee);}

Exemple 2. Opérateurs + et *

Page 77: Structures de données IFT-2000 Abder Alikacem Classes et objets en C++ Département d’informatique et de génie logiciel Édition Septembre 2009 Département

Surcharge des opérateurs

p1 + p2; est alors équivalent à: p1.operator +(p2);

C'est la méthode de l'instance de gauche qui est appelée. Donc, si on définit:

point point::operator +(int x){

point resultat;resultat.abscisse = abscisse + x;resultat.ordonnee = ordonnee;return resultat;

}

L'appel suivant est légal:p1 + 3;

Mais celui ci ne l'est pas: 3 + p1;

Page 78: Structures de données IFT-2000 Abder Alikacem Classes et objets en C++ Département d’informatique et de génie logiciel Édition Septembre 2009 Département

Surcharge des opérateurs

Quand l'opérateur + (par exemple) est appelé, le compilateur génère un appel à la fonction operator+. Ainsi, l'instruction

a = b + c;

Est équivalente aux instructions :

a = operator+(b, c); // fonction globalea = b.operator+(c); // fonction membre

Page 79: Structures de données IFT-2000 Abder Alikacem Classes et objets en C++ Département d’informatique et de génie logiciel Édition Septembre 2009 Département

Surcharge des opérateurs

Exercice

Utilisez la classe suivante pour écrire un programme qui crée un nouvel objet C par « addition » de deux objets A et B.

class X { public:

X& operator+(const X& arg){ X *x = new X(); x->n = n + arg.n; return *x;

}

int n; };

Page 80: Structures de données IFT-2000 Abder Alikacem Classes et objets en C++ Département d’informatique et de génie logiciel Édition Septembre 2009 Département

Surcharge des opérateurs

operator++ et operator−− sont ambigus : s’agit-il de la définition de l’opérateur suffixé ou préfixé ? Un paramètre artificiel int dans la définition permet de lever cette ambiguïté.

Exemple 3. Opérateurs ++ et --

class Pointeur { int * p;

public: Pointeur& operator++ (); // préfixe Pointeur operator++ (int); // suffixe Pointeur& operator-- (); // préfixe Pointeur operator-- (int); // suffixe int operator*() { return *p; } // déréférencement

};

Page 81: Structures de données IFT-2000 Abder Alikacem Classes et objets en C++ Département d’informatique et de génie logiciel Édition Septembre 2009 Département

Surcharge des opérateurs

Exemple 3. Opérateurs ++ et --

Écrivez une classe contenant au moins une donnée entière et dans laquelle les deux incrémentations et les deux décrémentations sont définies mais font +2et -2 en préfixé et +3 et -3 en infixé.

Exercice

Page 82: Structures de données IFT-2000 Abder Alikacem Classes et objets en C++ Département d’informatique et de génie logiciel Édition Septembre 2009 Département

Surcharge des opérateurs

L'utilité des classes est de pouvoir définir des objets qui soient aussi facile à utiliser que les types de base, ce n'est pas le cas du type Tableau que nous avons vu précédemment.

Par exemple, si T est une variable de type Tableau, on aimerait pouvoir Écrire T[i]=T[i]+1 plutôt que T.modifier(i,T.element(i)+1). Cela est possible en remplaçant les fonctions membres element et modifier par une modification(surcharge) de l'opérateur [].

class Tableau{private: int nbelements;

int *T;

public: Tableau(int);~Tableau();int longueur() const;int& operator[](int);

};

Exemple 4. Opérateur []

Page 83: Structures de données IFT-2000 Abder Alikacem Classes et objets en C++ Département d’informatique et de génie logiciel Édition Septembre 2009 Département

Surcharge des opérateurs

Tableau::Tableau(int n){

T=new int[n];nbelements=n;

}

Tableau::~Tableau(){

delete[] T;}

int Tableau::longueur() const{

return nbelements;}

int& Tableau::operator[](int i){

return T[i];}

La valeur retournée par la fonction operator[] est de type int& plutôt que int. Cela est essentiel si on veut pouvoir écrire:

Tableau tab(20);tab[0]=666;

Pour affecter la valeur 666 à l'objet tab.T[0] il est nécessaire que l'appel de la fonction tab[0] retourne l'objet lui-même plutôt qu'une simple copie.

Page 84: Structures de données IFT-2000 Abder Alikacem Classes et objets en C++ Département d’informatique et de génie logiciel Édition Septembre 2009 Département

Ces opérateurs permettant d'écrire ou de lire toutes sortes de données, types de base et tous les types désirés. Ils offrent en effet l'avantage de pouvoir les utiliser avec les opérateurs surchargés >> et << respectivement.

Surcharge des opérateurs

Exemple 5. Opérateurs << et >>

Il est possible de définir les opérateurs << et >> pour n’importe quel type et ainsi chaque objet peut être facilement manipulé par les flots de sorties (de type std::ostream) std::cout et std::cerr pour le standard et l’erreur respectivement et le flot d’entrée (de type std::istream) std::cin (Comme l’indique le préfixe std::, tous ces objets sont dans le namespace std).

Page 85: Structures de données IFT-2000 Abder Alikacem Classes et objets en C++ Département d’informatique et de génie logiciel Édition Septembre 2009 Département

Surcharge des opérateurs

Exemple 5… suite

Les opérateurs de flot << et >> peuvent aussi être redéfinis mais comme ils sont définis dans les classes « stream » ils ne peuvent être redéfinis dans une nouvelle classe…

Solution = fonction/méthode« friend »

class A { friend ostream& operator <<(ostream&, const A&); friend istream& operator >>(istream&, const A&);

public: A() {i=0; f=0.0;}; ~A() {};

private: int i; float f;

};

Page 86: Structures de données IFT-2000 Abder Alikacem Classes et objets en C++ Département d’informatique et de génie logiciel Édition Septembre 2009 Département

Ainsi, pour les nouvelles classes, on peut surcharger les fonctions friend :

std::ostream& operator<<(std::ostream&, const Type& obj);std::istream& operator>>(std::istream&, Type& obj);

Surcharge des opérateurs

Exemple 5… suite

ostream& operator <<(ostream& o, const A& a) {

o << "i = "<< a.i << " f= "<< a.f<< endl; return o;

}

istream& iperator >>(istream& i, const A& a) {

i >> a.i >> a.f; return i;

}

Exemple 1

Page 87: Structures de données IFT-2000 Abder Alikacem Classes et objets en C++ Département d’informatique et de génie logiciel Édition Septembre 2009 Département

Surcharge des opérateurs

Exemple 5… suite

class Complexe { float re, im; ... friend std::ostream& operator<< (std::ostream& o, const Complexe& c); friend std::istream& operator>> (std::istream& i, Complexe& c) ;

};

std::ostream& operator<< (std::ostream& o, const Complexe& c) {return o << c.re << ‘‘+’’ << c.im << ‘‘i’’;

}std::istream& operator>> (std::istream& i, Complexe& c) {

return i >> c.re >> c.im;}

Exemple 2

Page 88: Structures de données IFT-2000 Abder Alikacem Classes et objets en C++ Département d’informatique et de génie logiciel Édition Septembre 2009 Département

Surcharge des opérateurs

Exercice

Écrivez un programme dans lequel une classe contenant au moins deux chaînesde caractères « nom » et « prénom » avec des données privées et des méthodes publiques permettra de lire, écrire, saisir et afficher ces donnéesen redéfinissant les opérateurs de flots.

Page 89: Structures de données IFT-2000 Abder Alikacem Classes et objets en C++ Département d’informatique et de génie logiciel Édition Septembre 2009 Département

Surcharge des opérateurs

Exemple 6. Opérateurs == et <

class Date{public: bool operator== (const Date& obj) const; bool operator< (const Date& obj) const; friend std::ostream& operator<<(std::ostream& os, const Date& obj);private: long m_temps;};

bool Date::operator==(const Date& obj) const{ return m_temps == obj.m_temps;}bool Date::operator<(const Date& obj) const{ return m_temps < obj.m_temps;}

Page 90: Structures de données IFT-2000 Abder Alikacem Classes et objets en C++ Département d’informatique et de génie logiciel Édition Septembre 2009 Département

Surcharge des opérateurs

Exemple 6… suite

std::ostream& operator<<(std::ostream& os, const Date& obj){ os << obj.m_temps; return os;}

// --- Exemple d'utilisationint main(){ Date d1; Date d2(4,11,2001); bool bEgal = (d1 == d2); //--- d1.operator==(d2) bool bInferieur = (d1 < d2); //--- d1.operator<(d2) cout << d1 << endl; //--- operator<<(cout, d1) cout << d2 << endl; //--- operator<<(cout, d2) return 0;}

Page 91: Structures de données IFT-2000 Abder Alikacem Classes et objets en C++ Département d’informatique et de génie logiciel Édition Septembre 2009 Département

Le constructeur par copie est une méthode implicite dans toute classe.

Constructeur de copie

Cette méthode est appelée automatiquement dans les opérations suivantes :

Création et initialisation d ’une nouvelle instanceX I2=I1;X I2(I1);

passage d ’un argument par valeur retour d ’une fonction

return (I);// une copie de I est retournée

Utilisation

Page 92: Structures de données IFT-2000 Abder Alikacem Classes et objets en C++ Département d’informatique et de génie logiciel Édition Septembre 2009 Département

Constructeur de copie et opérateur d’affectation

Notre version de la classe Tableau ne se comporte pas encore tout à fait Comme un type de base. Par exemple, considérez le fragment de code suivant:

int a;int b=a;a=b;

Dans cet exemple, deux variables sont créées en faisant appel à deux constructeurs différents.

Dans le premier cas, le constructeur est de la forme int::int() alors que dans le second cas il est de la forme int::int(const int&).

On aurait d'ailleurs pu remplacer la seconde ligne par

int b(a);

Ainsi le symbole '=' n'a pas la même signification dans la secondeet dans la troisième ligne où il désigne l'opérateur d'affectation.

Page 93: Structures de données IFT-2000 Abder Alikacem Classes et objets en C++ Département d’informatique et de génie logiciel Édition Septembre 2009 Département

Constructeur de copie et opérateur d’affectation

On aimerait pouvoir écrire:

Tableau a(100) ;Tableau b=a;a=b;

Pour ce faire nous allons faire deux modifications. Nous allons surchargerl'opérateur = et nous allons définir un constructeur de copie, c'est-à-dire un constructeur de la forme: Tableau::Tableau(const Tableau&).

class Tableau{private: int nbelements;

int *T;public:

Tableau(int);Tableau(const Tableau&);~Tableau() {delete[] T;};int longueur() const {return nbelements;};int& operator[](int) const;Tableau& operator=(const Tableau&);

};

Page 94: Structures de données IFT-2000 Abder Alikacem Classes et objets en C++ Département d’informatique et de génie logiciel Édition Septembre 2009 Département

Constructeur de copie et opérateur d’affectation

Tableau::Tableau(int n){

T=new int[n];nbelements=n;

}

Tableau::Tableau(const Tableau &tab){

T=new int[tab.nbelements];(*this)=tab;

}

int& Tableau::operator[](int i) const {

return T[i];}

Page 95: Structures de données IFT-2000 Abder Alikacem Classes et objets en C++ Département d’informatique et de génie logiciel Édition Septembre 2009 Département

Constructeur de copie et opérateur d’affectation

Tableau& Tableau::operator=(const Tableau &tab){

if (nbelements<tab.nbelements){

delete[] T;T=new int[tab.nbelements];

}

nbelements=tab.nbelements;for (int i=0; i<nbelements; i++)T[i]=tab.T[i];

return *this;}

Page 96: Structures de données IFT-2000 Abder Alikacem Classes et objets en C++ Département d’informatique et de génie logiciel Édition Septembre 2009 Département

Constructeur de copie et opérateur d’affectation

Les fonctions membres peuvent être définies en même temps que leur déclaration comme c'est le cas du destructeur et de la fonction longueur().

On retrouve le mot clef const immédiatement après la liste des paramètresde longueur et de operator[]. Il indique donc que ces fonctions ne peuvent Pas modifier l'objet pour lequel ces fonctions sont appelées.

Ainsi dans l'exemple:Tableau A(20);int n=A[0];

le constructeur par copie et l'opérateur [] sont appelés pour le Tableau A qui ne doit pas être modifié par ces fonctions.

Finalement, l'expression this est un mot clef du C++ désignant le pointeurde l'objet pour lequel une fonction membre est appelée.

Page 97: Structures de données IFT-2000 Abder Alikacem Classes et objets en C++ Département d’informatique et de génie logiciel Édition Septembre 2009 Département

Le pointeur this

Dans une méthode, ou un constructeur, le mot-clé this est un pointeur sur l’objet considéré. Ainsi, lorsque l'on appelle une méthode d'une classe, celle-ci reçoit en plus de ses paramètres, un paramètre caché : le pointeur this.

Ce pointeur (constant) permet à la méthode d'accéder à l'objet quil'a appelé.

Exemple

Point& Point::copie(const Point& P) {if (this == &P) return *this; // ce n’est pas la peine de se copier soit même.// Attention, ce test vérifie l’égalité en adresse mémoire// et non l’égalité mathématique (celle des membres). x = P.x;this->y = P.y;

}

Page 98: Structures de données IFT-2000 Abder Alikacem Classes et objets en C++ Département d’informatique et de génie logiciel Édition Septembre 2009 Département

Constructeur de copie et opérateur d’affectation

Avec cette nouvelle version de la classe Tableau, il est maintenant beaucoup plus simple d‘écrire une fonction pour échanger le contenu de deux variables.

void echanger(Tableau &A, Tableau &B){

Tableau tmp=A;A=B;B=tmp;

}

Le problème de l'affectation d'un grand tableau dans un petit est résoluepar la surcharge que nous avons fait de l'opérateur =: un tableau trop petit est simplement remplacé par un autre de la dimension appropriée.

Page 99: Structures de données IFT-2000 Abder Alikacem Classes et objets en C++ Département d’informatique et de génie logiciel Édition Septembre 2009 Département

Constructeur de copie

Il y a donc un type spécial de constructeur, le constructeur de copie:

Si un constructeur de copie est spécifié, il sera appelé à chaque fois qu’un objet est rendu par une fonction, et à chaque fois qu’un objet est passé par valeur à une fonction.

C’est grâce au constructeur de copie que le programmeur évite un certain nombre de problèmes d’allocation de mémoire lorsque celle ci est référée par des variables membres de l’objet.

Page 100: Structures de données IFT-2000 Abder Alikacem Classes et objets en C++ Département d’informatique et de génie logiciel Édition Septembre 2009 Département

Constructeur de copie Toute classe a nécessairement un constructeur de copie. Lorsqu’aucun n’est défini explicitement, le compilateur en crée un automatiquement, qui se contente de recopier champ par champ l’argument dans this.

Le constructeur de copie n’est appelé (comme tout constructeur) que lors d’une initialisation. Donc, si on écrit :

c2 = c1;

Ce n’est pas le constructeur qui est appelé, mais l’opérateur d’affectation =, qui par défaut recopie les champs un à un ; il faut donc également le redéfinir.

Cette remarque met en relief un fait essentiel qui est que lors des deux écritures :

Exemple c2 = c1; // appel du constructeur de copiec2 = c1 // appel de l'opérateur d'affectation;

L’opérateur d’affectation n’est appelé qu’une fois (la seconde), tandis que c’est le constructeur de copie qui est appelé la première fois. Par défaut les deux appels provoquent le même effet ; Ce qui n'est pas le cas dans des classes définies par un programmeur.

Page 101: Structures de données IFT-2000 Abder Alikacem Classes et objets en C++ Département d’informatique et de génie logiciel Édition Septembre 2009 Département

Constructeur de copie

student& student::operator=(const student& s) {

if (&s == this)

return *this;

delete [] name;

name = new char[strlen(s.name) + 1];

strcpy(name,s.name);

return *this;

}

Exemple 1

Page 102: Structures de données IFT-2000 Abder Alikacem Classes et objets en C++ Département d’informatique et de génie logiciel Édition Septembre 2009 Département

Constructeur de copie

class classexmpl {public : classexmpl();

// constructeur par défautclassexmpl(int i); // un autre constructeurclassexmpl(classexmpl& c); // constructeur de copie

// autres méthodes...};

classexmpl c1; // constructeur par défaut

classexmpl c2 = c1; // appel du constructeur de copie// équivaut à classexmpl c2(c1);

Exemple 2

Page 103: Structures de données IFT-2000 Abder Alikacem Classes et objets en C++ Département d’informatique et de génie logiciel Édition Septembre 2009 Département

Constructeur de copie

class Obj{private: int* a;public: Obj();

~Obj();};

Obj::Obj(){

cout << " --> In Obj::Obj() " << endl;a = new int[10];for(int i=0; i<10;i++){a[i]=i;}

}

Obj::~Obj(){

cout << " --> In Obj::~Obj() " << endl;delete[] a; a = (int*)0;

}

void foo(Obj Inst){

cout << " --> In foo(Obj) " << endl;}

Exemple 3

Page 104: Structures de données IFT-2000 Abder Alikacem Classes et objets en C++ Département d’informatique et de génie logiciel Édition Septembre 2009 Département

Constructeur de copie

int main(){

Obj test;foo(test);

}

a

test

Dans foo(obj)

a

Copy de test

Allocation mémoire du tableau

Page 105: Structures de données IFT-2000 Abder Alikacem Classes et objets en C++ Département d’informatique et de génie logiciel Édition Septembre 2009 Département

Constructeur de copieint main(){

Obj test;foo(test);

}

a

test

Dans foo(obj)

a

Copy de test

Allocation mémoire du tableau de l'objet d'origine

Allocation mémoire de la copie de l'objet d'origine

Où les deux tableaux sont égales, valeurs par valeurs.

Page 106: Structures de données IFT-2000 Abder Alikacem Classes et objets en C++ Département d’informatique et de génie logiciel Édition Septembre 2009 Département

Constructeur de copie

class Obj{private: int* a;public:

Obj();Obj(const Obj&);~Obj();

};

Obj::Obj(const Obj& cpy){a = new int[10];for(int i=0; i<10;i++){

a[i]=cpy[i];}

}

La déclaration ressemble à :

Page 107: Structures de données IFT-2000 Abder Alikacem Classes et objets en C++ Département d’informatique et de génie logiciel Édition Septembre 2009 Département

Constructeur de copie et opérateur d’affectation

La double copie, qu’est ce que c’est ?

X d = X(a); //double copie

1/ création d ‘un objet temporaire qui est une copie de a => X(a) 2/ recopie de l ‘objet temporaire dans le nouvel objet d 3/ libération (appel au destructeur) de l ‘objet temporaire X(a)

Page 108: Structures de données IFT-2000 Abder Alikacem Classes et objets en C++ Département d’informatique et de génie logiciel Édition Septembre 2009 Département

Classe orthodoxe et canonique

La classe minimale correcte doit contenir les méthodes suivantes:

class X {

public: X() {...}; X(const X&) {...}; X& operator=(const X&) {...}; ~X() {...};

} ;

On parle alors de classes selon la forme de Coplien : une classe doit impérativement contenir un constructeur par défaut, un constructeur de recopie, un destructeur et une surcharge de l'opérateur d'affectation.

Page 109: Structures de données IFT-2000 Abder Alikacem Classes et objets en C++ Département d’informatique et de génie logiciel Édition Septembre 2009 Département

Un « cauchemar » avec les const!!

class X {public:

const int * const int_ptr(const int) const; };

const int * const X::int_ptr(const int i) const { static const int ii = 10; static const int * const ptr = &ii; return ptr;

}

const X x; const int i = 20;

cout << *(x.int_ptr(i)) << endl;

Page 110: Structures de données IFT-2000 Abder Alikacem Classes et objets en C++ Département d’informatique et de génie logiciel Édition Septembre 2009 Département

Opérateur de portée ::

L’opérateur de portée « :: » permet d’Accéder aux données et aux fonctions statiques des classes, mais aussi aux variables globales.

class X {

public:static int i;static const int I = 1;

};

class Y {public:

static int i;static const int I = 3;

};

int X:: i;int Y:: i;int i; const int I = 2;

int main(){int i; const int I =4;i = I;::i = ::I;X::i = X::I;Y::i = Y::I;cout << i << ::i;cout << X::i <<

Y::i;cout << endl;return 0;

}

Page 111: Structures de données IFT-2000 Abder Alikacem Classes et objets en C++ Département d’informatique et de génie logiciel Édition Septembre 2009 Département

Conversion de types

Il y a une conversion implicite vers un objet d’une classe s’il existe un constructeur ayant pour paramètre la valeur à convertir.

class X {

public:X() { n = 0;};X(int i) { n = i;};

private:int n;

};

X x = 0;

0 est converti en un objetX(0) car le constructeurX(int) existe.

Page 112: Structures de données IFT-2000 Abder Alikacem Classes et objets en C++ Département d’informatique et de génie logiciel Édition Septembre 2009 Département

Il y a une conversion implicite vers un objet d’une classe s’il existe un constructeur ayant pour paramètre la valeur à convertir.

class X {

public:X() { n = 0;};X(int i) { n = i;};

private:int n;

};

X x (0);

0 est converti en un objetX(0) car le constructeurX(int) existe.

Conversion de types

Page 113: Structures de données IFT-2000 Abder Alikacem Classes et objets en C++ Département d’informatique et de génie logiciel Édition Septembre 2009 Département

Il y a une conversion implicite vers un objet d’une classe s’il existe un constructeur ayant pour paramètre la valeur à convertir.

class X {

public:X() { n = 0;};X(int i) { n = i;};

private:int n;

};

X x (0);

0 est converti explicitementEn en un objet X(0) avant recopie dans x.

Conversion de types

Page 114: Structures de données IFT-2000 Abder Alikacem Classes et objets en C++ Département d’informatique et de génie logiciel Édition Septembre 2009 Département

C++ permet de définir ses propres fonctions de conversion vers d’autres types prédéfinis, ou d’autres classes.

Syntaxe: operator<type> ( )

class X {

public:X() { n = 0;};X(int i) { n = i;};operator int () const {return n;};

private:int n;

};

X x = 10;

int b = a;int c = int(a);

Conversion de types

Page 115: Structures de données IFT-2000 Abder Alikacem Classes et objets en C++ Département d’informatique et de génie logiciel Édition Septembre 2009 Département

Exemple d’une string

Conversion de types

Il peut être intéressant de définir une conversion en const char* pour passer facilement en argument de beaucoup de librairies.

Il s'agit ici de déterminer ce qui est préférable :conversion implicite ou conversion explicite?

Page 116: Structures de données IFT-2000 Abder Alikacem Classes et objets en C++ Département d’informatique et de génie logiciel Édition Septembre 2009 Département

Exemple d’une string

Conversion de types

class string{public: operator const char* () const;

const char* c_str () const;private: char* m_strP;};// --- Conversion implicitestring::operator const char*() const{ return m_strP;}// --- Conversion expliciteconst char* string::c_str() const{ return m_strP;}

Page 117: Structures de données IFT-2000 Abder Alikacem Classes et objets en C++ Département d’informatique et de génie logiciel Édition Septembre 2009 Département

Exemple d’une string

Conversion de types

// --- fopen (const char* fP) est une fonction du // --- C standard qui permet d'ouvrir un fichier.int main(){ string nomFichier("fichier.txt");

// --- Conversion implicite, i.e. appel // --- de l'opérateur de conversion en const char* FILE *file1P = fopen(nomFichier);

// --- Conversion explicite, i.e. appel // --- explicite de la méthode string::c_str(). FILE *file2P = fopen(nomFichier.c_str());

return 0;}

Il faut éviter les conversions implicites :On ne contrôle pas ce qui ce passe et on risque d'avoir des surprises et des imprévus...

Page 118: Structures de données IFT-2000 Abder Alikacem Classes et objets en C++ Département d’informatique et de génie logiciel Édition Septembre 2009 Département

Conversion de types

Il est possible comme on l’a déjà vu de convertir un type vers un autre en passant par un constructeur.

Exemple d’une string :

• Un char* peut être convertis en string parce que la string a défini un constructeur avec un const char* :

string (const char* strP); conversion implicite.

• La string pourrait avoir un constructeur acceptant un double. - Pour contrôler quand cette conversion se fera : ajouter le mot-clé explicit devant le constructeur : explicit string (double d); conversion explicite.

Page 119: Structures de données IFT-2000 Abder Alikacem Classes et objets en C++ Département d’informatique et de génie logiciel Édition Septembre 2009 Département

Conversion de types

class string{public: string(const char* strP); explicit string(double d);private: char* m_strP;};

string::string(const char* strP){ m_strP = new char[strlen(strP)+1]; strcpy(m_strP, strP);}

string::string(double d){ ostringstream os; os << d; *this = os.str();}

Exemple d’une string :

Page 120: Structures de données IFT-2000 Abder Alikacem Classes et objets en C++ Département d’informatique et de génie logiciel Édition Septembre 2009 Département

Conversion de types

void foo (string str);

int main(){ double d = 2.2;

// --- Conversion implicite par le constructeur foo ("Bonjour la police");

// Error : no implicit conversion from double to string foo (d);

// --- Ok: appel explicite pour la conversion foo (string(d)); return 0;}

Exemple d’une string :

Page 121: Structures de données IFT-2000 Abder Alikacem Classes et objets en C++ Département d’informatique et de génie logiciel Édition Septembre 2009 Département

Pour conclure, en C++ deux syntaxes sont préférées :

float re = float(a) est un appel au constructeur de float, de paramètre un entier.

float re = static_cast<float>(a) est un transtypage plus contraint, donc plus précis. En C++, il existe trois autres transtypages possibles :

dynamic_cast qui permet de réaliser des conversions valides, vérifiées à l’exécution, mais que le compilateur n’arrive pas à faire (car il ne connaît pas encore le véritable type – un template, par exemple –). reinterpret_cast est utilement atroce (permet par exemple de transformer un int en une adresse de pointeur). const_cast permet d’ajouter ou de retirer un qualificatif const (le comportement ensuite peut-être non spécifié).

Conversion de types

Page 122: Structures de données IFT-2000 Abder Alikacem Classes et objets en C++ Département d’informatique et de génie logiciel Édition Septembre 2009 Département

Écrivez un programme dans lequel une classe Entier représente les entiers et permet de mélanger les objets instance de la classe Entier avec les véritables entiers dans les expressions arithmétiques contenant les quatre opérations de base. Ajoutez aussi les opérateurs de flots << et >>.

Exercice

Conversion de types

Page 123: Structures de données IFT-2000 Abder Alikacem Classes et objets en C++ Département d’informatique et de génie logiciel Édition Septembre 2009 Département

Portée des identificateurs

Il y en a 5!

Portée globalePortée de fichierPortée de bloc

Portée de classePortée de l’espace de nommage

Page 124: Structures de données IFT-2000 Abder Alikacem Classes et objets en C++ Département d’informatique et de génie logiciel Édition Septembre 2009 Département

Portée globale

L’allocation de mémoire est faite statiquement à la compilation, initialisation à 0 (comme toutes les variables globales non initialisées en C).

…int N;…int a =N + 1;

N est connu dans toute l’application, les autresFichiers doivent la déclarer « extern » pour Pouvoir y accéder sans la dupliquer.

Portée des identificateurs

Page 125: Structures de données IFT-2000 Abder Alikacem Classes et objets en C++ Département d’informatique et de génie logiciel Édition Septembre 2009 Département

Portée de fichier

L’allocation de mémoire est faite statiquement à la compilation, initialisation à 0 (comme toutes les variables globales non initialisées en C).

…static int N;…int a =N + 1;

N est connu dans le fichier seulement, les autres fichiers ne peuvent y accéder, mêmes’ils déclarent une autre variable N ou tente de la qualifier « extern ».

Portée des identificateurs

Page 126: Structures de données IFT-2000 Abder Alikacem Classes et objets en C++ Département d’informatique et de génie logiciel Édition Septembre 2009 Département

Portée de bloc

L’allocation de mémoire est faite dynamiquement dans la pile.

{…{

…int N;…

}…

}

N n’est connu que dans cette zone.

C’est-à-dire après sa déclaration et jusqu’àLa fermeture du bloc englobant.

Portée des identificateurs

Page 127: Structures de données IFT-2000 Abder Alikacem Classes et objets en C++ Département d’informatique et de génie logiciel Édition Septembre 2009 Département

Portée de bloc

{…{

…static int N;…

}…

}

N n’est connu que dans cette zone.

C’est-à-dire après sa déclaration et jusqu’àLa fermeture du bloc englobant.

L’allocation de mémoire est faite statiquement à la compilation, initialisation à 0 (comme toutes les variables globales non initialisées en C).

Portée des identificateurs

Page 128: Structures de données IFT-2000 Abder Alikacem Classes et objets en C++ Département d’informatique et de génie logiciel Édition Septembre 2009 Département

Portée de classe

Un identificateur de membre d’une classe ne peut être utilisé que:

- Dans une fonction membre de la classe- Après l’opérateur « . » appliqué à un objet instance de la classe- Après l’opérateur « -> » appliqué à un pointeur sur un objet instance de la classe- Après l’opérateur de résolution de portée appliqué à la classe

Portée des identificateurs

Page 129: Structures de données IFT-2000 Abder Alikacem Classes et objets en C++ Département d’informatique et de génie logiciel Édition Septembre 2009 Département

Portée de classe Dans une fonction membre de la classe

class X {

public:int a() { return b() + c();}

private:int b() {…};int c() {…};int d() { return 2* a();}

};

Portée des identificateurs

Page 130: Structures de données IFT-2000 Abder Alikacem Classes et objets en C++ Département d’informatique et de génie logiciel Édition Septembre 2009 Département

Portée de classe Après l’opérateur « . » appliqué à un objet instance de la classe

class X {

public:int a() { return b() + c();}

private:int b() {…};int c() {…};int d() { return 2* a();}

};

X x;cout << x.a() << endl;

Portée des identificateurs

Page 131: Structures de données IFT-2000 Abder Alikacem Classes et objets en C++ Département d’informatique et de génie logiciel Édition Septembre 2009 Département

Portée de classe Après l’opérateur « ->. » appliqué à un pointeur sur un objet instance de

la classe

class X {

public:int a() { return b() + c();}

private:int b() {…};int c() {…};int d() { return 2* a();}

};

X *x = new X();cout << x->a() << endl;

Portée des identificateurs

Page 132: Structures de données IFT-2000 Abder Alikacem Classes et objets en C++ Département d’informatique et de génie logiciel Édition Septembre 2009 Département

Portée de classe Après l’opérateur de résolution de portée appliqué à la classe

class X {

public:static void A() {…};int a() { return b() + c();}

private:int b() {…};int c() {…};int d() { return 2* a();}

};

X:: A();

Portée des identificateurs

Page 133: Structures de données IFT-2000 Abder Alikacem Classes et objets en C++ Département d’informatique et de génie logiciel Édition Septembre 2009 Département

Portée d’espace de nommagePourquoi ?

Lorsque l’on se linke avec uneBibliothèque on réutilise les idfsQui y sont définis. On ne peut pasDéfinir d’idf ayant le même nomQue l’un quelconque des idfs de la Bibliothèque dans son programme.Il y aurait une « double définition »,Fatale pour le linker…

namespace <idf> {<declarations>

}

Portée des identificateurs

Page 134: Structures de données IFT-2000 Abder Alikacem Classes et objets en C++ Département d’informatique et de génie logiciel Édition Septembre 2009 Département

Portée d’espace de nommageComment ?

Chaque fournisseur de bibliothèqueDoit encapsuler ses déclarations dansUn espace de nommage.

Les STL, les librairies standards du C++,Sont dans l’espace de nommage « std ».

namespace <idf> {<declarations>

}

Portée des identificateurs

Page 135: Structures de données IFT-2000 Abder Alikacem Classes et objets en C++ Département d’informatique et de génie logiciel Édition Septembre 2009 Département

Portée d’espace de nommage

Espace de nommage « anonyme » est équivalent à l’usage de « static » mais sansavoir besoin de « static » devant les déclarations.

namespace {<declarations>

}

En effet, le standard veut que tous les symboles déclarés dans un espace de Nommage anonyme aient comme portée le fichier seulement.

Portée des identificateurs

Page 136: Structures de données IFT-2000 Abder Alikacem Classes et objets en C++ Département d’informatique et de génie logiciel Édition Septembre 2009 Département

Portée d’espace de nommage

Pour faire référence à un idf d’un espace de nommage : deux situation.

Qualification <nom de l’espace>:: idf« using » using namespace <nom de l’espace>

Portée des identificateurs

Page 137: Structures de données IFT-2000 Abder Alikacem Classes et objets en C++ Département d’informatique et de génie logiciel Édition Septembre 2009 Département

Portée d’espace de nommage

Il est possible d’imbriquer des espaces de nommage.Il est également possible de créer des alias.

namespace toto {<declarations>namespace tutu {…}

}

namespace titi = toto::tutu;

Portée des identificateurs

Page 138: Structures de données IFT-2000 Abder Alikacem Classes et objets en C++ Département d’informatique et de génie logiciel Édition Septembre 2009 Département

Constantes non constantes!!

1. Ce n’est pas une blague de mauvais goût!2. Ce sont des membres dits « mutables »3. Mutable n’est pas compatible avec const et static4. Mutable signifie « ne sera jamais constant »

Permet au programmeur de changer la valeur d’une donnée membre mêmeSi l’objet dans lequel elle se trouve est déclaré comme constant!

class X {

public:X(int a =4) {i = a;};int lireI() const { return i++;};

private:mutable int i;

};

const X x;cout << x.lireI() << endl;cout << x.lireI() << endl;

Page 139: Structures de données IFT-2000 Abder Alikacem Classes et objets en C++ Département d’informatique et de génie logiciel Édition Septembre 2009 Département

Le traitement des exceptions

Le C++ contient un mécanisme très utile pour traiter les erreurs et autres exceptions.

Lorsqu'une erreur est détectée, il est possible de transmettre (throw)un objet à une partie du code qui reçoit (catch) l'objet et traite l'erreur.

Considérons, par exemple, la fonction operator[] de la classe Tableau. Il serait prudent de vérifier la valeur de l'opérande afin de s'assurer qu'elle corresponde bien à un indice valide du tableau. Si tel n'est pas le cas, que doit faire la fonction? Elle ne dispose pas de l'information nécessaire pour traiter elle-même l'erreur et ne peut pas signaler l'erreur par une valeur de retour ou un paramètre.

Pour régler ce problème nous allons ajouter un membre publique et modifier la fonction operator[]. C’est une solution parmi tant d’autres, nousreviendrons plus en détails sur la gestion des exceptions dans un autre Chapitre dédié uniquement sur ce concept.

Page 140: Structures de données IFT-2000 Abder Alikacem Classes et objets en C++ Département d’informatique et de génie logiciel Édition Septembre 2009 Département

Le traitement des exceptions

template<class elem>class Tableau{

elem nbelements;elem *T;

public:struct erreur_indice{

int indice;erreur_indice(int i){indice=i;};

};

Tableau(int);Tableau(const Tableau&);~Tableau() {delete[] T;};int longueur() const {return nbelements;};elem& operator[](int) const;Tableau& operator=(const Tableau&);

};

Page 141: Structures de données IFT-2000 Abder Alikacem Classes et objets en C++ Département d’informatique et de génie logiciel Édition Septembre 2009 Département

Le traitement des exceptions

template<class elem>elem& Tableau<elem>::operator[](const int i) const{

if (i<0 || i>=nbelements) throw erreur_indice(i);

return T[i];}

Nous avons ajouté à Tableau la définition d'une structure afin de définirun type d'erreur correspondant aux dépassement des limites.

En C++ une structure est exactement comme une classe sauf que par défaut les membres sont publiques. Si operator[] détecte une erreur, il utilisera le constructeur de erreur_indice pour créer un objet qu'il transmettra via l'instruction throw. L'instruction throw se comporte un peu comme l'instruction return sauf qu'elle cherche dans la pile des appels de fonctions celle qui demande à recevoir l'objet.

Page 142: Structures de données IFT-2000 Abder Alikacem Classes et objets en C++ Département d’informatique et de génie logiciel Édition Septembre 2009 Département

Le traitement des exceptions

Exempletemplate<class elem>void initialise(Tableau<elem>& t, const elem& E){

for (int i=0; i<=t.longueur(); i++)t[i]=E;

}

int main(){

Tableau<int> T(100);try{

initialise(T,0);}catch(Tableau<int>::erreur_indice e){

cerr<<"Erreur d'indice: <<e.indice<<endl;}

return 0;}

Page 143: Structures de données IFT-2000 Abder Alikacem Classes et objets en C++ Département d’informatique et de génie logiciel Édition Septembre 2009 Département

Le traitement des exceptions

La fonction main() utilise les mots clefs try et catch pour indiquer qu'elleappelle la fonction initialise et qu'elle désire traiter les erreurs de typeTableau<int>::erreur_indice.

Au dernier tour de boucle de initialise, l'indice i aura dépassé les limites du tableau et Tableau<int>::operator[] transmettra un objet de type Tableau<int>::erreur_indice qui sera reçu par la fonction main().

Page 144: Structures de données IFT-2000 Abder Alikacem Classes et objets en C++ Département d’informatique et de génie logiciel Édition Septembre 2009 Département

Le traitement des exceptions

Plusieurs catch peuvent apparaître après un try afin de recevoir et traiter plusieurs types d'erreurs.

L'expression catch(...) permet de recevoir tous les types d'erreurs non capturés par les catch précédents:

try{instructions

}catch(type 1){

instructions}catch(type 2){

instructions}catch(...){

instructions}

Page 145: Structures de données IFT-2000 Abder Alikacem Classes et objets en C++ Département d’informatique et de génie logiciel Édition Septembre 2009 Département

Le traitement des exceptions

L’importance de ce sujet nous fera revenir plus longuement dans un autre Chapitre dédié uniquement sur ce concept.