31
Fabio Hernandez [email protected] Programmation Orientée Objet en C++ Programmation Orientée Objet en C++ 10ème Partie: Classes Génériques 10ème Partie: Classes Génériques

Partie 10: Classes Génériques — Programmation orientée objet en C++

Embed Size (px)

DESCRIPTION

Support material for a continued education course "Introduction to object oriented programming in C++". In French.

Citation preview

Page 1: Partie 10: Classes Génériques — Programmation orientée objet en C++

Fabio [email protected]

Programmation Orientée Objet en C++Programmation Orientée Objet en C++

10ème Partie: Classes Génériques10ème Partie: Classes Génériques

Page 2: Partie 10: Classes Génériques — Programmation orientée objet en C++

© 1997-2003 Fabio HERNANDEZ314POO en C++: Classes Génériques

Vue d'EnsembleVue d'Ensemble

Notions de base Types, variables, opérateursContrôle d'exécutionFonctionsMémoire dynamiqueQualité du logicielEvolution du modèle objet Objets et classesFonctions membresClasses génériquesHéritagePolymorphismeHéritage multipleEntrée/sortie

Page 3: Partie 10: Classes Génériques — Programmation orientée objet en C++

© 1997-2003 Fabio HERNANDEZ315POO en C++: Classes Génériques

Table des MatièresTable des Matières

MotivationDéclaration d'une classe génériqueUtilisationImplémentation des fonctions membresConsidérations particulièresFonctions génériquesContraintesCoût vs. BénéficeRésumé

Page 4: Partie 10: Classes Génériques — Programmation orientée objet en C++

© 1997-2003 Fabio HERNANDEZ316POO en C++: Classes Génériques

MotivationMotivation

Nous avons étudié les facilités offertes par C++ pour créer des classes permettant de définir des conteneurs d'objets d'un même typeUn conteneur est un objet qui agit sur une collection de zéro ou plusieurs objets d'une classe particulièreLes classes List et Queue et les tableaux sont des exemples des classes conteneursLe type des objets contenus dans un objet de la classe List ou de la classe Queue est floatLes services de ces classes (append, prepend, insert,remove,...) ne dépendent pas du type des objets qu'elles contiennent

Page 5: Partie 10: Classes Génériques — Programmation orientée objet en C++

© 1997-2003 Fabio HERNANDEZ317POO en C++: Classes Génériques

Motivation (suite)Motivation (suite)

Supposons que nous voulons créer une List d'objets de type char

Une possible solution consiste à dupliquer le code déjà écrit pour la classe List en faisant les modifications pour que les objets contenus soient de type char et pas float

il faudrait aussi renommer les classes (FloatList, CharList,...)cette solution pose des problèmes pour la maintenance du code

Une autre possible solution est d'utiliser les facilités de définition de macros du pré-processeur pour générer le code nécessaire sur demande du programmeur

problèmes de maintenanceparticulièrement inélégant

Page 6: Partie 10: Classes Génériques — Programmation orientée objet en C++

© 1997-2003 Fabio HERNANDEZ318POO en C++: Classes Génériques

Motivation (suite)Motivation (suite)

C++ fournit un mécanisme permettant de définir des classes (et des fonctions) génériques (paramétrables)L'idée est d'écrire des "moules" permettant de construire d'autres classes

particulièrement utile pour les conteneursle paramètre de la classe correspond au type des objets contenus

En C++ cette facilité est connue sous le nom de template

Nous allons étudier à nouveau la classe List et la modifier de façon à ce qu'elle devienne générique

Page 7: Partie 10: Classes Génériques — Programmation orientée objet en C++

© 1997-2003 Fabio HERNANDEZ319POO en C++: Classes Génériques

Contrôle d'AvancementContrôle d'Avancement

MotivationDéclaration d'une classe génériqueUtilisationImplémentation des fonctions membresConsidérations particulièresFonctions génériquesContraintesCoût vs. BénéficeRésumé

Page 8: Partie 10: Classes Génériques — Programmation orientée objet en C++

© 1997-2003 Fabio HERNANDEZ320POO en C++: Classes Génériques

DéclarationDéclaration

#if !defined(LIST_H_INCLUDED)#define LIST_H_INCLUDED

template <class Item>class List {public:

// Constructors/DestructorList();List(int initialCapacity);List(const List& aList);~List();

// Modifiersbool append(Item anItem);bool prepend(Item anItem);bool insert(Item anItem, int position);bool remove(Item anItem);

Item est le paramètre de la classe List

Page 9: Partie 10: Classes Génériques — Programmation orientée objet en C++

© 1997-2003 Fabio HERNANDEZ321POO en C++: Classes Génériques

Déclaration (suite)Déclaration (suite)

bool removeAll(Item anItem);bool replace(int position, Item anItem);bool replaceAll(Item item1, Item item2);void clear();

// Selectorsint length() const;int occurrences(Item anItem) const;int position(Item anItem) const;Item itemAt(int position) const;Item first() const;Item last() const;bool isEqual(const List& aList) const;bool isEmpty() const;

Page 10: Partie 10: Classes Génériques — Programmation orientée objet en C++

© 1997-2003 Fabio HERNANDEZ322POO en C++: Classes Génériques

Déclaration (suite)Déclaration (suite)

private:// Data membersItem* data_;int capacity_;int length_;

// Help functionsvoid resize();

};

#endif // LIST_H_INCLUDED

Page 11: Partie 10: Classes Génériques — Programmation orientée objet en C++

© 1997-2003 Fabio HERNANDEZ323POO en C++: Classes Génériques

Contrôle d'AvancementContrôle d'Avancement

MotivationDéclaration d'une classe génériqueUtilisationImplémentation des fonctions membresConsidérations particulièresFonctions génériquesContraintesCoût vs. BénéficeRésumé

Page 12: Partie 10: Classes Génériques — Programmation orientée objet en C++

© 1997-2003 Fabio HERNANDEZ324POO en C++: Classes Génériques

UtilisationUtilisation

Pour utiliser (créer une instance d') une classe générique il faut fournir les paramètres nécessairesFichier main.cpp

#include "List.h"

void main() {

List<char> alphabet;

alphabet.append('z');

alphabet.prepend('a');

if (alphabet.isEmpty())

...

cout << "Length = " << alphabet.length() << endl;

...

}

Création d’une instance de la classe

générique avec le type primitif char comme

paramètre

Page 13: Partie 10: Classes Génériques — Programmation orientée objet en C++

© 1997-2003 Fabio HERNANDEZ325POO en C++: Classes Génériques

Utilisation (suite)Utilisation (suite)

De façon similaire pour les listes des autres types primitifsList<float> hitList;

List<int> counterList;

...

On peut aussi créer des instances des classes génériques avec comme paramètre d'autres classes

#include "Point.h"

#include "List.h"

List<Point> vertexList; // A List of Point objects

Page 14: Partie 10: Classes Génériques — Programmation orientée objet en C++

© 1997-2003 Fabio HERNANDEZ326POO en C++: Classes Génériques

Utilisation (suite)Utilisation (suite)

Notez que les instances des classes génériques sont complètement identifiées par le nom de la classe et ses paramètres

List<int> counterList;

List<char> alphabet;

...

// COMPILATION ERROR: 'counterList' and

// 'alphabet' are two objets of a different class

if (counterList.isEqual(alphabet))

cout << "They are equal" << endl;

Page 15: Partie 10: Classes Génériques — Programmation orientée objet en C++

© 1997-2003 Fabio HERNANDEZ327POO en C++: Classes Génériques

Utilisation (suite)Utilisation (suite)

Afin de faciliter l'écriture, on peut définir des synonymes#include "List.h"

typedef List<char> CharList;

...

CharList alphabet;

alphabet.clear();

for(char letter='a'; letter <= 'z'; ++letter)

alphabet.append(letter);

...

Définition d'un synonyme d'une

classe générique

Page 16: Partie 10: Classes Génériques — Programmation orientée objet en C++

© 1997-2003 Fabio HERNANDEZ328POO en C++: Classes Génériques

Contrôle d'AvancementContrôle d'Avancement

MotivationDéclaration d'une classe génériqueUtilisationImplémentation des fonctions membresConsidérations particulièresFonctions génériquesContraintesCoût vs. BénéficeRésumé

Page 17: Partie 10: Classes Génériques — Programmation orientée objet en C++

© 1997-2003 Fabio HERNANDEZ329POO en C++: Classes Génériques

ImplémentationImplémentation

Spécificités syntaxiques liées à la "généricité"Exemple

template<class Item>Item List<Item>::first() const{

assert(length_ > 0);return data_[0];

}

template<class Item>inlinebool List<Item>::isEmpty() const{

return (length_ == 0) ? true : false;}

Page 18: Partie 10: Classes Génériques — Programmation orientée objet en C++

© 1997-2003 Fabio HERNANDEZ330POO en C++: Classes Génériques

Implémentation (suite)Implémentation (suite)

L'implémentation des fonctions membres doit être contenue (directe ou indirectement) lorsque l'on inclut le fichier de l'interfaceFichier List.h

#if !defined(LIST_H_INCLUDED)

#define LIST_H_INCLUDED

template <class Item>class List {public:

...private:

...};

Page 19: Partie 10: Classes Génériques — Programmation orientée objet en C++

© 1997-2003 Fabio HERNANDEZ331POO en C++: Classes Génériques

Implémentation (suite)Implémentation (suite)

Fichier List.h (suite)template<class Item>Item List<Item>::first() const{

...}

template<class Item>inlinebool List<Item>::isEmpty() const{

...}

...

#endif // LIST_H_INCLUDED

Page 20: Partie 10: Classes Génériques — Programmation orientée objet en C++

© 1997-2003 Fabio HERNANDEZ332POO en C++: Classes Génériques

Paramètres des Classes GénériquesParamètres des Classes Génériques

Spécification de plusieurs paramètrestemplate <class T1, class T2, class T3>

class ComplicatedClass {

public:

...

private:

...

};

Création d'un objet de cette classeComplicatedClass<float, int, Point> complicatedObject;

Page 21: Partie 10: Classes Génériques — Programmation orientée objet en C++

© 1997-2003 Fabio HERNANDEZ333POO en C++: Classes Génériques

Paramètres des Classes Génériques (suite)Paramètres des Classes Génériques (suite)

Les paramètres peuvent aussi être des expressionstemplate <class Type, int Size>

class Buffer {

...

};

UtilisationBuffer<double,256> littleBuffer;

Buffer<char,1024*10> bigBuffer;

const int MaxSize = 100;

Buffer<bool,MaxSize> answerBuffer;

Page 22: Partie 10: Classes Génériques — Programmation orientée objet en C++

© 1997-2003 Fabio HERNANDEZ334POO en C++: Classes Génériques

Contrôle d'AvancementContrôle d'Avancement

MotivationDéclaration d'une classe génériqueUtilisationImplémentation des fonctions membresConsidérations particulièresFonctions génériquesContraintesCoût vs. BénéficeRésumé

Page 23: Partie 10: Classes Génériques — Programmation orientée objet en C++

© 1997-2003 Fabio HERNANDEZ335POO en C++: Classes Génériques

Considérations ParticulièresConsidérations Particulières

Cette implémentation fonctionne-t-elle aussi bien pour les objets complexes que pour les objets des types primitifs?

template <class Item>

bool List<Item>::append(Item anItem)

{

if (length_ == capacity_)

resize();

data_[length_] = anItem;

++length_;

return true;

}

Page 24: Partie 10: Classes Génériques — Programmation orientée objet en C++

© 1997-2003 Fabio HERNANDEZ336POO en C++: Classes Génériques

Considérations Particulières (suite)Considérations Particulières (suite)

Nous devrions plutôt la modifier comme

template <class Item>

bool List<Item>::append(const Item& anItem)

{

if (length_ == capacity_)

resize();

data_[length_] = anItem;

++length_;

return true;

}

De façon similaire pour les autres fonctions membres

Page 25: Partie 10: Classes Génériques — Programmation orientée objet en C++

© 1997-2003 Fabio HERNANDEZ337POO en C++: Classes Génériques

Contrôle d'AvancementContrôle d'Avancement

MotivationDéclaration d'une classe génériqueUtilisationImplémentation des fonctions membresConsidérations particulièresFonctions génériquesContraintesCoût vs. BénéficeRésumé

Page 26: Partie 10: Classes Génériques — Programmation orientée objet en C++

© 1997-2003 Fabio HERNANDEZ338POO en C++: Classes Génériques

Fonctions GénériquesFonctions Génériques

Syntaxe similaire à celle des classes

template <class Type>Type min(Type a, Type b){

return (a < b) ? a : b;}

template <class Item>ostream& operator<<(ostream& stream,

const List<Item>& aList){

...return stream;

}

Page 27: Partie 10: Classes Génériques — Programmation orientée objet en C++

© 1997-2003 Fabio HERNANDEZ339POO en C++: Classes Génériques

Contrôle d'AvancementContrôle d'Avancement

MotivationDéclaration d'une classe génériqueUtilisationImplémentation des fonctions membresConsidérations particulièresFonctions génériquesContraintesCoût vs. BénéficeRésumé

Page 28: Partie 10: Classes Génériques — Programmation orientée objet en C++

© 1997-2003 Fabio HERNANDEZ340POO en C++: Classes Génériques

ContraintesContraintes

L'implémentation des fonctions membres d'une classe générique impose des contraintes sur les classes utilisées comme paramètre du templateExemple

la fonction membreint List<Item>::position(const Item& anItem) const

suppose que la classe Item fournit l'opérateur d'égalitéla fonction membre

int List<Item>::append(const Item& anItem)

suppose que la classe Item fournit l'opérateur d'affectationL'instance ne pourra pas être créée si ces suppositions ne sontpas satisfaites au moment de la compilation

Page 29: Partie 10: Classes Génériques — Programmation orientée objet en C++

© 1997-2003 Fabio HERNANDEZ341POO en C++: Classes Génériques

Contrôle d'AvancementContrôle d'Avancement

MotivationDéclaration d'une classe génériqueUtilisationImplémentation des fonctions membresConsidérations particulièresFonctions génériquesContraintesCoût vs. BénéficeRésumé

Page 30: Partie 10: Classes Génériques — Programmation orientée objet en C++

© 1997-2003 Fabio HERNANDEZ342POO en C++: Classes Génériques

CoûtCoût vsvs. Bénéfice. Bénéfice

Avantagesmécanisme très puissant

Inconvénientssyntaxe dissuasivepas encore (bien) supporté par quelques compilateurstemps de compilation/édition de liens augmentétaille de l'exécutable augmentée

Page 31: Partie 10: Classes Génériques — Programmation orientée objet en C++

© 1997-2003 Fabio HERNANDEZ343POO en C++: Classes Génériques

RésuméRésumé

Les classes génériques servent pour décrire des conteneurs indépendamment du type des objets contenusLe client de la classe générique doit fournir les types nécessaires pour la création de l’instance de la classe génériqueL'implémentation des classes génériques suppose une attention particulière puisque le type de chaque paramètre n'est pas connu à prioriBien que normalisé, ce mécanisme n'est pas encore supporté par tous les compilateurs