La présentation est en train de télécharger. S'il vous plaît, attendez

La présentation est en train de télécharger. S'il vous plaît, attendez

Structures de données IFT-10541

Présentations similaires


Présentation au sujet: "Structures de données IFT-10541"— Transcription de la présentation:

1 Structures de données IFT-10541
Abder Alikacem Programmation orienté objet en C++ Module 2 Édition Septembre 2009 Département d’informatique et de génie logiciel

2 Plan Introduction au mondes des objets: les concepts
01/04/2017 Plan Introduction au mondes des objets: les concepts Le concept d'Objet Les principes de l’Approche Orientée Objet Les relations entre Objets Quelques définitions Principe de l’encapsulation Classes et objets Les modèles (templates) Programmation générique : introduction, exemples Déclaration des modèles Fonctions et méthodes génériques Instanciation Spécialisation Compilation séparée Traitement des exceptions Vice-rectorat à la recherche / octobre 2005

3 Le concept d’objet (1/3) Exemple : une personne, une voiture, une procédure, une loi, ... Objet : abstraction du monde réel entité possédant un état (information) offrant des services / opérations pour examiner / modifier son état (comportement) Modèle Orienté-Objet (OO) d’une application : définition d’un ensemble d’objets coopérants - communicants - et concurrents - vivants indépendamment les uns des autres

4 Le concept d’objet (2/3) Objet = identité + état + comportement
Exemple : la voiture 1875 WC 31 état : immatriculation, kilométrage, vitesse instantanée, état interne… services / opérations : accesseurs : kilométrage?, immatriculation? ... modificateurs : démarrer, s’arrêter, se déplacer, tomber en panne, être réparée ... Essentiel : un objet n'est manipulable qu'à travers son interface i.e. ses opérations publiques

5 Le concept d'objet (3/3) Tout objet a une durée de vie finie : il naît, vit et meurt ! Tout objet est en relation avec d'autres objets : relations statiques : (relativement) stables dans le temps relations dynamiques : brèves, limitées à la communication Tout objet peut changer de forme - sous certaines conditions - au cours de son existence : principe de polymorphisme

6 Principes sur lesquels reposent les Objets
Encapsulation : regroupement des informations d'état et de comportement sous un nom unique Masquage d'information : on ne connaît pas la structure de l'information Interface : seuls les services publics (offerts à l'extérieur) sont utilisables Envoi de messages : les objets communiquent par messages Durée de vie limitée : dépendante du contexte

7 Les relations entre Objets
Relations statiques : composition / agrégation : traduit l'assemblage généralisation / spécialisation : permet la réutilisation association n-aire : relation classique Relations dynamiques : communication : échange de données signal : échange de stimuli

8 Généralisation / spécialisation
Généralisation : a posteriori pour favoriser la réutilisation future Spécialisation : c'est de la réutilisation en extension : ajout de nouvelles propriétés en compréhension : modification de propriétés Conséquences : Polymorphisme : possibilité pour une instance de changer de classe tout en restant dans la même hiérarchie Héritage simple / multiple

9 Représentation d'objet
Son nom Son état Opération publique La voiture de Jean kilométrage? kilométrage : ... vitesse : ... immatriculation : ... démarrer Un objet tomber en panne ... Opération privée

10 Quelques définitions Classe = regroupement d'objets ayant des propriétés (état et/ou comportement et/ou relations) communes Classe = moule qui décrit la structure interne d'un ensemble d'objets Classe = abstraction qui n'a de sens qu'à la compilation Objet = un instance d'une classe Objet = instance qui n'a d'existence qu'à l'exécution

11 Propriétés des objets Unicité :
un objet n'est instance que d'une classe et d'une seule une instance a une identité (interne) unique Durée de vie : une instance doit être déclarée, puis définie en fonction du contexte. un objet vit sa vie puis meurt. la durée de vie peut être très courte, très grande ! Polymorphisme : un objet peut changer de forme au cours de sa vie ! Concurrence : les objets évoluent indépendamment les uns des autres

12 Conception Orientée Objet
Deux étapes fondamentalement différentes : Identification des classes à réutiliser ou à concevoir : utilisation d’une méthode OO pour la conception et la définition des hiérarchies de classes à utiliser ou à développer Construction de l’Application OO : transformation de la conception de l’application en un ensemble d’objets concurrents et coopérants

13 Intérêt des Objets Maîtrise de la complexité :
l'encapsulation permet de se concentrer sur un(e) objet(classe) et un(e) seul(e) il est possible de tester de façon quasi exhaustive un objet Evolution facilitée : rajouter de nouveaux objets est simplifié. On les raccroche aux modèles déjà construits par spécialisation Réutilisation : vraiment possible à cause des classifications induites par la relation de spécialisation / généralisation ! ...

14 Inconvénients de l'approche OO
Tout n'est pas objet : se méfier des chapelles et des gourous ! Tester un ensemble un système OO est difficile ! Penser objet oblige à changer de mentalité !

15 Encapsulation, polymorphisme et héritage
01/04/2017 Encapsulation, polymorphisme et héritage Encapsulation Le rassemblement des données et du code les utilisant dans une entité unique (objet). La séparation nette entre la partie publique d'un objet (ou interface) seule connue de l'utilisateur de la partie privée ou implémentation qui reste masquée. Polymorphisme Une méthode peut adopter plusieurs formes différentes. Héritage Possibilité de définir des familles de classes traduisant le principe de généralisation / spécialisation. « La classe dérivée est une version spécialisée de sa classe de base » Vice-rectorat à la recherche / octobre 2005

16 Encapsulation et abstraction
01/04/2017 Encapsulation et abstraction L'encapsulation Consiste à masquer l'accès à certains attributs et méthodes d'une classe. Pourquoi masquer? Cacher les détails d'implémentation des objets à l'utilisateur permet de modifier, par exemple la structure de données interne d'une classe (remplacer un tableau par une liste chaînée) sans pour autant entraîner de modifications dans le code de l’utilisateur, l’interface n’étant pas atteinte. Abstraction de données La structure d'un objet n'est pas visible de l'extérieur, son interface est constituée de messages invocables par un utilisateur. La réception d'un message déclenche l'exécution de la méthode correspondant à ce message. Abstraction procédurale Du point de vue de l'extérieur (c’est-à-dire en fait du client de l’objet), l'invocation d'un message est une opération atomique. L'utilisateur n'a aucun élément d'information sur la mécanique interne mise en œuvre. Par exemple, il ne sait pas si le traitement requis a demandé l’intervention de plusieurs méthodes ou même la création d’objets temporaires etc. Vice-rectorat à la recherche / octobre 2005

17 01/04/2017 Droits d’accès En C++, on choisit les paramètres d’accès aux membres d’une encapsulation à l'aide des mots clés : private : les membres privés ne sont accessibles que par les fonctions membres de la classe. protected : les membres protégés sont comme les membres privés. Mais ils sont aussi accessibles par les fonctions membres des classes dérivées. public : les membres publics sont accessibles par tous. La partie publique est appelée interface. Les mots réservés private , protected et public peuvent figurer plusieurs fois dans la déclaration de la classe. Le droit d'accès ne change pas tant qu'un nouveau droit n'est pas spécifié. Vice-rectorat à la recherche / octobre 2005

18 Les différents type d’encapsulation
01/04/2017 Les différents type d’encapsulation Il existe différents types d’encapsulation : struct Classe1 { /* ... */ }; tous les membres sont par défaut d'accès public par défaut. union Classe2 { /* ... */ }; tous les membres sont d'accès public par défaut. class Classe3 { /* ... */ }; tous les membres sont d'accès private par défaut. C'est cette dernière forme qui est utilisée en C++ pour définir des classes. Vice-rectorat à la recherche / octobre 2005

19 Principe de la conception orienté objet
01/04/2017 Principe de la conception orienté objet Algorithmes + Structures de données = Programme Approche traditionnelle Organiser autour du traitement Fonction 1 Fonction 2 Structures de données Fonction 3 Fonction n Vice-rectorat à la recherche / octobre 2005

20 Principe de la conception orienté objet
01/04/2017 Principe de la conception orienté objet Organiser autour des données à manipuler Données Fonctions de manipulations et de traitements Objet Vice-rectorat à la recherche / octobre 2005

21 Objet en C++ Programme C++ Programme C Class Date { typedef struct {
01/04/2017 Objet en C++ Programme C++ Programme C typedef struct { int jour; int mois; int année; } Date; void initData(Data d,int j,int m,int a){ d.jour=j; d.mois=m; d.année=a; } int main(){ Date d; initData(d,2,2,2004); return 0; Class Date { public : void initData(int j,int m,int a); protected: int _jour; int _mois; int _année; }; Date::initData(int j,int m,int a){ _jour=j; _mois=m; _année=a; } int main(){ Date d; d.initData(2,2,2004); return 0; Vice-rectorat à la recherche / octobre 2005

22 Interface d’une classe (fichier .h)
01/04/2017 Interface d’une classe (fichier .h) class Date { public : int var1; Date(); ~Date(); void initialiser(int j,int m,int a); void afficher(); int getJour(); int getMois(); int getAnnee(); setJour( int j); setMois(int m); setAnnee(int a); protected: int _jour; int _mois; int _année; void _test(); private: }; Section public Attributs public Méthodes public Constructeur Destructeur Fonction d’accès Section protected Attributs et méthodes accessibles par les membres de la classe et des classes dérivées Section private Attributs et méthodes accessibles uniquement par les membres de la classe Vice-rectorat à la recherche / octobre 2005

23 Implantation d’une classe (fichier .cpp)
01/04/2017 Implantation d’une classe (fichier .cpp) Date::Date(){ _jour=0; _mois_0; _annee=0; } Date::~Date(){} void Data::afficher(){ cout << "la date : " << _jour ; cout << "/" << _mois ; cout << "/" << _annee << endl; int Data::getJour() {return _jours;} int Data::getMois() {return _mois;}; int Data::getAnnee(){return _annee;} Data::setJour(int j) {_jour =j;} Data::setMois(int m) {_mois =m;} Data::setAnnee(int a){_annee=a;} Définition des méthodes de la class : Constructeur Destructeur Fonction d’accès Vice-rectorat à la recherche / octobre 2005

24 Réutilisabilité On cherche à écrire des objets réutilisables.
01/04/2017 Réutilisabilité On cherche à écrire des objets réutilisables. On aimerait concevoir une classe qui modélise une pile de portée générale : une pile n’importe quels composants. pile<char> Pcar; pile <personne> Ppersonne; ==> Concevoir une classe générique Vice-rectorat à la recherche / octobre 2005

25 Facteur de qualité d’un logiciel
01/04/2017 Facteur de qualité d’un logiciel Une classe décrit une famille d ’objets : Cohérente Lisible Extensible Réutilisable Réutilisabilité Possibilité d ’obtenir toutes les occurrences d ’une classe s ’appliquant à différents types, en ne décrivant qu’une seule fois la classe. Vice-rectorat à la recherche / octobre 2005

26 Programmation générique
01/04/2017 Programmation générique L’idée de base est de passer les types de données comme paramètres pour décrire des traitements très généraux (« génériques »). Il s’agit donc d’un niveau d’abstraction supplémentaire. De tels modèles de classes/fonctions s’appellent aussi classes/fonctions génériques ou patrons (chablons), ou encore « template ». Vous en connaissez déjà sans le savoir. Par exemple la « classe » Vector de la STL n’est en fait pas une classe mais un modèle de classes : c’est le même modèle que l’on stocke des char (vector<char>), des int (vector<int>), ou tout autre objet. Vice-rectorat à la recherche / octobre 2005

27 Programmation générique
01/04/2017 Programmation générique Exemple simple pour commencer Prenons un exemple simple pour commencer : une fonction échangeant la valeur de 2 variables. Par exemple avec 2 entiers vous écririez une fonction comme : // échange la valeur de ses arguments void echange(int& i, int& j) { int tmp(i); i = j; j = tmp; } Mais vous vous rendez bien compte que vous pourriez faire la même chose (le même algorithme) avec deux double, ou même deux objets quelconques, pour peu qu’ils aient un constructeur de copie (Obj tmp(i);) et un opérateur de copie (operator=). Vice-rectorat à la recherche / octobre 2005

28 Programmation générique
01/04/2017 Programmation générique Exemple suite… L’écriture générale serait alors quelque chose comme : // échange la valeur de ses arguments void echange(Type& i, Type& j) { Type tmp(i); i = j; j = tmp; } où Type est une représentation générique du type des objets à échanger. La façon exacte de le faire en C++ est la suivante : template<typename Type> Vice-rectorat à la recherche / octobre 2005

29 Programmation générique
01/04/2017 Programmation générique Exemple suite…et fin On pourra alors utiliser la fonction echange avec tout type/classe pour lequel le constructeur de copie et l’opérateur d’affectation (=) sont définis. Par exemple : int a(2), b(4); echange(a,b); double da(2.3), db(4.5); echange(da,db); vector<double> va, vb; ... echange(va,vb); string sa("ca marche"), sb("coucou"); echange(sa, sb); Vice-rectorat à la recherche / octobre 2005

30 Programmation générique
01/04/2017 Programmation générique Second exemple d’une fonction générique template <class X > X min (const X& A,const X& B){ if (A<B) return(A); return (B); } L ’opérateur < doit être surchargé dans les classes qui utiliseront le modèle min intmain (){ int i,j,m; cin >> i,j; int m=min <int>(i,j); ... } Le compilateur instancie une fonction int min (const int&, const int&) Vice-rectorat à la recherche / octobre 2005

31 Programmation générique
01/04/2017 Programmation générique Généralisation aux classes Une classe générique est une classe avec un template. Même principe que les fonctions génériques. template <typename T> class Nb{ public : T a, b; T add (){ return a+b}; }; Nb<int> N; N.a = 1; N.b = 2; cout << N.Add() << endl; Vice-rectorat à la recherche / octobre 2005

32 Programmation générique
01/04/2017 Programmation générique Généralisation aux classes On pourrait par exemple vouloir créer une classe qui réalise une paire d’objets quelconques : template<typename T1, typename T2> class Paire { public: Paire(const T1& un, const T2& deux) : premier(un), second(deux) {} virtual ˜Paire(){} T1 get1() const { return premier; } T2 get2() const { return second; } void set1(const T1& val) { premier = val; } void set2(const T2& val) { second = val; } protected: T1 premier; T2 second; }; Vice-rectorat à la recherche / octobre 2005

33 Programmation générique
01/04/2017 Programmation générique Généralisation aux classes et par exemple créer la classe « paire string–double » : Paire<string,double> ou encore la classe « paire char–unsigned int » : Paire<char,unsigned int> Note : un tel modèle de classe existe dans la STL : pair. Les modèles de classes sont donc un moyen condensé d’écrire plein de classes potentielles à la fois. Vice-rectorat à la recherche / octobre 2005

34 Programmation générique
01/04/2017 Programmation générique Déclaration d’un modèle Pour déclarer un modèle de classe ou de fonction, il suffit de faire précéder sa déclaration du mot clé template suivit de ses arguments (qui sont donc des noms génériques de type) suivant la syntaxe : template<typename nom1, typename nom2, ...> Exemple template<typename T1, typename T2> class Paire { ... Le paramètre générique effectif d ’une classe peut être un identificateur de type prédéfini ou un identificateur de classe. Vice-rectorat à la recherche / octobre 2005

35 Programmation générique
01/04/2017 Programmation générique Déclaration d’un modèle Pour déclarer un modèle de classe ou de fonction, il suffit de faire précéder sa déclaration du mot clé template suivit de ses arguments (qui sont donc des noms génériques de type) suivant la syntaxe : template<typename nom1, typename nom2, ...> Exemple template<typename T1, typename T2> class Paire { ... Les types ainsi déclarés (paramètres du modèle) peuvent alors être utilisés dans la définition qui suit, exactement comme tout autre type. Note : on peut aussi utiliser le mot class à la place de typename, par exemple : template<class T1, class T2> Vice-rectorat à la recherche / octobre 2005

36 Programmation générique
01/04/2017 Programmation générique Définitions externes des méthodes de modèles de classes Si les méthodes d’un modèle de classes sont définies en dehors de cette classe, elle devront alors aussi être définies comme modèle et être précédées du mot clé template, mais il est de plus absolument nécessaire d’ajouter les paramètres du modèle (les types génériques) au nom de la classe [ pour bien spécifier que dans cette définition c’est la classe qui est en modèle et non la méthode. ] Exemple template<typename T1, typename T2> class Paire { public: Paire(const T1&, const T2&); ... }; // définition du constructeur template<typename T1, typename T2> Paire<T1,T2>::Paire(const T1& un, const T2& deux) : premier(un), second(deux) { } Vice-rectorat à la recherche / octobre 2005

37 Programmation générique
01/04/2017 Programmation générique Instanciation des modèles La définition des modèles ne génère en elle-même aucun code : c’est juste une description de plein de codes potentiels. Le code n’est produit que lorsque tous les paramètres du modèle ont pris chacun un type spécifique. Lors de l’utilisation d’un modèle, il faut donc fournir des valeurs pour tous les paramètres (au moins ceux qui n’ont pas de valeur par défaut). On appelle cette opération une instanciation du modèle. L’instanciation peut être implicite lorsque le contexte permet au compilateur de décider de l’instance de modèle à choisir. Par exemple, dans le code : double da(2.3), db(4.5); echange(da,db); il est clair (par le contexte) qu’il s’agit de l’instance echange<double> du modèle template<typename T> void echange(T&,T&); qu’il faut utiliser. Vice-rectorat à la recherche / octobre 2005

38 Programmation générique
01/04/2017 Programmation générique Instanciation des modèles Mais dans la plupart des cas, on explicite l’instanciation lors de la déclaration d’un objet. C’est ce qui vous faites lorsque vous déclarez par exemple vector<double> tableau; Il suffit dans ce cas de spécifier le(s) type(s) désiré(s) après le nom du modèle de classe et entre <>. L’instanciation explicite peut aussi être utile dans les cas où le contexte n’est pas suffisamment clair pour choisir. Par exemple avec le modèle de fonction template <typename Type> Type monmax(const Type& x, const Type& y) { if (x < y) return y; else return x; } l’appel monmax(3.14, 7); est ambigu. Il faudra alors écrire monmax<double>(3.14, 7); Vice-rectorat à la recherche / octobre 2005

39 Programmation générique
01/04/2017 Programmation générique Modèles, surcharge et spécialisation Les modèles de fonctions peuvent très bien être surchargés comme les fonctions usuelles (puisque, encore une fois, ce sont juste une façon condensée d’écrire plein de fonctions à la fois). Par exemple : template<typename Type> void affiche(const Type& t) { cout << "J’affiche " << t << endl; } // surcharge pour les pointeurs : on préfère ici écrire // le contenu plutôt que l’adresse. template<typename Type> void affiche(Type* t) { cout << "J’affiche " << *t << endl; Note : on aurait même pu faire mieux en écrivant : affiche<Type>(*t); qui fait appel au premier modèle. Vice-rectorat à la recherche / octobre 2005

40 Programmation générique
01/04/2017 Programmation générique Modèles, surcharge et spécialisation Mais les modèles (y compris les modèles de classes) offrent un mécanisme supplémentaire : la spécialisation qui permet de définir une version particulière d’une classe ou d’une fonction pour un choix spécifique des paramètres du modèle. Par exemple, on pourrait spécialiser le second modèle ci-dessus dans le cas des pointeurs sur des entiers : template<> void affiche<int>(int* t) { cout << "J’affiche le contenu d’un entier: " << *t << endl; } La spécialisation d’un modèle (lorsqu’elle est totale) se fait en : ajoutant template<> devant la définition nommant explicitement la classe/fonction spécifiée C’est le <int> après affiche dans l’exemple ci-dessus. Vice-rectorat à la recherche / octobre 2005

41 Programmation générique
01/04/2017 Programmation générique Exemple de spécialisation de classe template<typename T1, typename T2> class Paire { ... }; // spécialisation pour les paires <string,int> template<> class Paire<string,int> { public: Paire(const string& un, int deux) : premier(un), second(deux) {} virtual ˜Paire() {} string get1() const { return premier; } int get2() const { return second; } void set1(const string& val) { premier = val; } void set2(int val) { second = val; } // une méthode de plus void add(int i) { second += il } protected: string premier; int second; Vice-rectorat à la recherche / octobre 2005

42 Programmation générique
01/04/2017 Programmation générique Spécialisation: remarques Note 1 : La spécialisation peut également s’appliquer uniquement à une méthode d’un modèle de classe sans que l’on soit obligé de spécialiser toute la classe. Utilisée de la sorte, la spécialisation peut s’avérer particulièrement utile. Note 2 : La spécialisation n’est pas une surcharge car il n’y a pas génération de plusieurs fonctions de même nom (de plus que signifie une surcharge dans le cas d’une classe ?) mais bien une instance spécifique du modèle. Note 3 : il existe aussi des spécialisations partielles (de classe ou de fonctions), mais cela nous emmènerait trop loin dans ce cours. Vice-rectorat à la recherche / octobre 2005

43 Programmation générique
01/04/2017 Programmation générique Exemple 2 template <typename T, int taille_max = 200> // Le paramètre entier max_size a la valeur 200 par défaut. class pile { public: typedef T value_type; private: T* laPile ; int sommet ; public: pile() : sommet(0) { laPile = new T [taille_max] ; } ~pile() { delete [] laPile ; } void empiler ( T c ) { laPile[ sommet++ ] = c ; } // ... }; Vice-rectorat à la recherche / octobre 2005

44 Programmation générique
01/04/2017 Programmation générique Retour sur le typename Le mot clef typename indique que le mot suivant doit être considéré comme un type. C’est le cas dans une déclaration template (où typename peut aussi être remplacé par class) et dans les cas où il y aurait ambiguïté ou si le type n’est pas encore instancié (paramètre d’un autre type, lui-même template). template <class P, int taille_max = 200> class SacADos { // P::value_type n’est pas encore un type puisque T, n’a pas été instancié // Il faut donc l’indiquer au compilateur typedef typename P::value_type T_values; ... }; Vice-rectorat à la recherche / octobre 2005

45 Programmation générique
01/04/2017 Programmation générique Fonctions et méthodes génériques template permet aussi de déclarer des fonctions génériques, voire des fonctions membres génériques d’une classe générique. Cependant, ici, la spécification entre < et > n’est pas requise à l’appel car déduite des paramètres effectifs. int main() { pile p ; // instanciation d’une pile. char c = ’a’; // Ces appels sont valides. // Dans le premier cas ‘‘char’’ est déduit //du type de c. p.empiler(c); p.empiler<char>(c) ; explorer( p ); explorer<pile>( p ); return 0; } class pile { template <class T> void empiler(const T& a); .... }; template<class X> void explorer(const X& p) { ... }; Vice-rectorat à la recherche / octobre 2005

46 Programmation générique
01/04/2017 Programmation générique Exemple 3 Il est possible de créer des Tableaux d'entiers, de les manipuler comme les variables d'un type intégré et de les passer en paramètre sans avoir à fournir la taille comme paramètre supplémentaire. Cependant notre solution ne fonctionne que pour des Tableaux d'entiers. Que se passe-t-il si on avait besoin de Tableaux de doubles ou de chaînes de caractères? On voudrait pouvoir créer des Tableaux de types arbitraires sans avoir à définir une classe distincte pour chacun d'eux. Cela peut être fait à l'aide des modèles (templates). Vice-rectorat à la recherche / octobre 2005

47 Programmation générique
01/04/2017 Programmation générique template<class elem> class Tableau{ private: int nbelements; int *T; public: Tableau(int); Tableau(const Tableau&); ~Tableau() {delete[] T;}; int longueur() const {return nbelements;}; elem& operator[](int) const; Tableau& operator=(const Tableau&); }; Rappel: on peut écrire template <class elem> outemplate <typename elem> Vice-rectorat à la recherche / octobre 2005

48 Programmation générique
01/04/2017 Programmation générique template<class elem> Tableau<elem>::Tableau(int n) { T=new elem[n]; nbelements=n; } template<class elem> Tableau<elem>::Tableau(const Tableau<elem> &tab) T=new elem[tab.nbelements]; (*this)=tab; template<class elem> elem& Tableau<elem>::operator[](const int i) const return T[i]; Vice-rectorat à la recherche / octobre 2005

49 Programmation générique
01/04/2017 Programmation générique template<class elem> Tableau<elem>& Tableau<elem>::operator=(const Tableau<elem> &tab) { if (nbelements<tab.nbelements) delete[] T; T=new elem[tab.nbelements]; } nbelements=tab.nbelements; for (int i=0; i<nbelements; i++) T[i]=tab.T[i]; return *this; Vice-rectorat à la recherche / octobre 2005

50 Programmation générique
01/04/2017 Programmation générique La définition de la classe est précédée de templace<class elem> qui indique que l'on défini un modèle et qu'un type elem apparaît en argument dans la déclaration de Tableau. On peut alors déclarer un tableau d'entiers ou de double de la façon suivante: Tableau<int> iTab(100); Tableau<double> dTab(20); Vice-rectorat à la recherche / octobre 2005

51 Programmation générique
01/04/2017 Programmation générique Les modèles ne sont pas retreints aux classes comme on l’a déjà vu et comme l'illustre les exemples suivants: template<class C> void echanger(C &A, C &B) { C tmp=A; A=B; B=tmp; } template<class elem> void print(const Tableau<elem>& t) for (int i=0; i<t.longueur(); i++) cout<<t[i]<<" "; cout<<endl; Vice-rectorat à la recherche / octobre 2005

52 Programmation générique
01/04/2017 Programmation générique La fonction echanger ne peut être utilisée que par une classe C possédant un constructeur de copie et un opérateur d'affectation. La fonction print nécessite que l'opérateur << soit défini pour les objets de type elem. On peut appeler ces fonctions de la façon suivante: int a=0, b=1; double x=1.0, y=2.3; Tableau<int> A(20), B(30); Tableau<char> C(100) // // initialisation de A, B et C echanger(a,b); echanger(x,y); echanger(A,B); print(A); print(B); print(C); Vice-rectorat à la recherche / octobre 2005

53 Programmation générique
01/04/2017 Programmation générique Modèles de classe et compilation séparée Les modèle de classes doivent nécessairement être définis au moment de leur instanciation afin que le compilateur puisse générer le code correspondant. Ce qui implique, lors de compilation séparée, que les fichiers d’en-tête (.h) doivent contenir non seulement la déclaration, mais également la définition complète de ces modèles !! On ne peut donc pas séparer la déclaration de la définition dans différents fichiers... Ce qui présente plusieurs inconvénients : Les mêmes instances de modèles peuvent être compilées plusieurs fois, et se retrouvent en de multiples exemplaires dans les fichiers exécutables. On ne peut plus cacher leurs définitions (par exemple pour des raisons de confidentialité, protection contre la concurrence, etc...) Vice-rectorat à la recherche / octobre 2005

54 Programmation générique
01/04/2017 Programmation générique Modèles de classe et compilation séparée Notez également que les fichiers contenant des modèles ne sont pas des fichiers sources classiques, puisque sans instanciation, ils ne génèrent aucun code machine. Pour résoudre ces problèmes, le langage C++ donne en principe la possibilité d’exporter les définitions des modèles dans des fichiers complémentaires à l’aide de la directive export. Malheureusement celle-ci n’est pour l’instant (à ma connaissance) pas gérée par les compilateurs actuels : warning: keyword ‘export’ not implemented, and will be ignored En l’état, il faut donc malheureusement joindre prototype et définitions des modèles dans les mêmes fichiers d’en-tête. Le seul « point noir » des templates est donc lié à la faiblesse des compilateurs actuels qui ne gèrent pas la directive export. Vice-rectorat à la recherche / octobre 2005

55 Programmation générique
01/04/2017 Programmation générique Templates Déclarer un modèle de classe ou de fonction : template<typename nom1, typename nom2, ...> Définition externe des méthodes de modèles de classes : NomClasse<nom1, nom2, ...>::NomMethode(... Instanciation : spécifier simplement les types voulus après le nom de la classe/fonction, entre <> (Exemple : vector<double>) Spécialisation (totale) de modèle pour les types type1, type2... : template<> NomModele<type1,type2,...> ...suite de la declaration... Compilation séparée : pour les templates, il faut tout mettre (déclarations et définitions) dans le fichier d’en-tête (.h). Vice-rectorat à la recherche / octobre 2005

56 Le traitement des exceptions
01/04/2017 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[]. Vice-rectorat à la recherche / octobre 2005

57 Le traitement des exceptions
01/04/2017 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&); Vice-rectorat à la recherche / octobre 2005

58 Le traitement des exceptions
01/04/2017 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éfinir un 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. Vice-rectorat à la recherche / octobre 2005

59 Le traitement des exceptions
01/04/2017 Le traitement des exceptions template<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; Exemple: Vice-rectorat à la recherche / octobre 2005

60 Le traitement des exceptions
01/04/2017 Le traitement des exceptions La fonction main() utilise les mots clefs try et catch pour indiquer qu'elle appelle la fonction initialise et qu'elle désire traiter les erreurs de type Tableau<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(). Vice-rectorat à la recherche / octobre 2005

61 Le traitement des exceptions
01/04/2017 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){ catch(type 2){ catch(...){ Vice-rectorat à la recherche / octobre 2005


Télécharger ppt "Structures de données IFT-10541"

Présentations similaires


Annonces Google