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 Introduction au langage C++ Édition Septembre 2009 Département d’informatique et de génie logiciel

2 Plan Introduction Un C amélioré Nouveaux types Techniques objets

3 Introduction Cette partie du cours suppose comme pré requis le langage C. Quelques vérités la programmation orientée objet n‘est pas le C++ on peut programmer « orienté objet » en C++ on peut programmer « sans objets » en C++

4 Introduction C date de 1972 son créateur est Dennis Ritchie(Bell Labs) il a été normalisé en 1989 ANSIX C++ date de 1980 son créateur est Bjarne Stroustrup (Bell Labs)

5 Introduction « hello world » en C++ #include <stdio.h>
int main(){ printf("hello world\n"); return 0; } #include <iostream> int main(){ cout << "hello world" << endl; return 0; }

6 Un C amélioré Commentaires Nombre variable d’arguments Constantes
Déclarations et définitions Prototypage de fonctions Surdéfinition de fonctions Arguments par défaut Fonctions « en ligne» Passage par référence Nombre variable d’arguments Types composés Conversion de types Résolution de portée Edition de liens Allocation dynamique Fonctions génériques Entrées-sorties Différences entre C et C++

7 Deux types de commentaires …
Un C amélioré Les commentaires Deux types de commentaires … type« bloc» type« ligne» /* blablabla blablabla */ // blablabla Une« surprise», que fait ceci en C et en C++ ? x = a //* divisons par b */b

8 Un C amélioré Les constantes
L ‘utilisation du préprocesseur C est une source d’erreurs difficiles à détecter. En C++ l ‘utilisation du préprocesseur est réduite à: la compilation conditionnelle et à l ‘inclusion de fichiers #ifdef toto #endif #include « toto.h

9 Un C amélioré Les constantes
Le préprocesseur n ‘est plus utilisé pour définir des constantes avec des « #define» dans les .h En C++ il y a le mot clé « const » pour définir les constantes. #define K 1024 const int K = 1024; « const » signifie que la donnée définie ne peut être modifiée

10 Un C amélioré Les constantes
Les contrôles concernant les constantes sont faits statiquement à la compilation et le fait que les constantes soient déclarées comme des variables n‘affecte en rien les performances du programme au moment de l‘exécution. Il est donc inutile en C++ (bien que cela soit possible) de conserver des constantes du genre « #define» pour tenter d‘économiser de la place ou accélérer le programme. Il vaut mieux confier ce type d‘optimisations au compilateur.

11 Un C amélioré Les constantes const int i = 7;
const double pi = ; const char titre[] = "toto"; const int x; i++; titre[3] = ‘ a ’;

12 Un C amélioré Les pointeurs constants int i = 0; // variable int j;
int* const iptr = &i; i=1; //ok *iptr = 2; // ok iptr = &j; // non Pointeur constant sur une variable

13 Un C amélioré Les pointeurs constants const int n = 0; // constante
const int p = 1; // constante int* const nptr = &n; // non const int* const pptr = &p; // ok *pptr = 2; // interdit pptr = &n; // interdit pptr = nptr; // interdit Pointeur constant sur une constante

14 Un C amélioré Déclarations et définitions de variables
const int N = 10; int i; for(i=0; i<N; i++) {…} int deuxN = N *2; for(int j=0; j<deuxN; j++) {…} if (int k = get()) { i=k;} else {j= k; } while (int m = get()) { i += m}; switch (int n = get()) { case 0: i = 1*n; break; case 1: i = 2*n; break; default: i = 3*n; break; } On déclare une variable quand on en a besoin.

15 Un C amélioré surdéfinitions de fonctions
Il est permis de définir dans un même programme deux ou plusieurs fonctions portant le même nom. Cela implique que ces fonctions doivent Différer au niveau de leur prototype/signature double add(double a, double b){ return a + b; } int add(int a, int b){ return a + b; } (int, add, int, int) (double, add, double, double) int i = add(1, 2); double d = add(1.0, 2.0);

16 Un C amélioré Arguments par défaut
Les arguments d’une fonction peuvent avoir des valeurs par défaut pour les paramètres formels de fin. Si, lors d’un appel, les paramètres correspondants ne sont pas spécifiés, alors les valeurs par défaut sont utilisées. double add(double a, double b = 2.0){ return a + b; } double d = add(1.0, 2.0); double dd = add(1.0);

17 Un C amélioré Fonctions « en ligne »
Il est possible de définir des fonctions « en ligne ». Le compilateur, à chaque appel de la fonction mise « en ligne », ne provoque pas un appel classique de fonction mais insère à cet endroit le code de la fonction dans lequel les paramètres formels sont remplacés par les paramètres effectifs. inline double add(double a, double b){ return a + b; } La mise « en ligne » permet d’Accélérer l’exécution d’un programme en supprimant l’appel de fonction, le passage des paramètres dans la pile, puis le retour de fonction.

18 Un C amélioré Passage d’arguments par référence
En C++, on peut passer par référence sans avoir à manipuler l’adresse explicitement en utilisant un synonyme d’une variable. void add(int a, int b, int &sum) { sum = a + b; } int A, B, SUM; A = 0; B = 1; SUM = 2; cout << SUM << endl; add(A, B, SUM);

19 Un C amélioré Conversion de types Les conversions de type sont
explicites ou implicites Le programmeur « décide » Le compilateur « décide »

20 notation fonctionnelle
Un C amélioré Conversion de types Les conversions explicites (type) expression notation fonctionnelle (type) expression Comme en C a) int i; long l; l = long(i); int i; long l; l = (long) i; b) #include <stdio.h> int main() { for(int i = 0; i <=255; i++) printf("%d --> %c", i, char(i)); return 0; }

21 Un C amélioré Conversion de types
Les conversions explicites Le « haut de gamme » de la conversion … const_cast<T>(e) Comme T(e) ou (T)e mais ne modifie que « const » ou « volatile » const char *a = "abcd"; char *b = a; // NON char *c = const_cast<char *>a; // OK

22 Un C amélioré Conversion de types
Les conversions explicites Le « haut de gamme » de la conversion … reinterpret_cast<T>(e) Utilisé pour réinterpréter complètement un type: ce n’est Pas une simple conversion entre nombres entiers et/ou réels int i; char *cptr; cptr = reinterpret_cast<char *>(i);

23 Un C amélioré Conversion de types
Les conversions explicites Le « haut de gamme » de la conversion … dynamic_cast<T>(e) Réservé aux objets, sera vu plus tard

24 Un C amélioré L’opérateur de résolution de portée « :: »
Permet d’accéder à des identificateurs globaux qui seraient Masqués par des identificateurs locaux. int i; int f() { i = ::i; } i local i gobal

25 Un C amélioré L’édition des liens
La gestion des symboles concernant les noms ne se fait absolument plus comme en C! En C, à toute fonction toto() correspond un symbole _toto qui permet de linker un programme appelant avec une bibliothèque contenant le code(et donc Le symbole _toto) de la fonction toto(). En C++, à cause du concept de surdéfinition de fonction, cela n ‘est plus possible. En effet, comment différencier à l‘aide du symbole _add les deux fonctions add(int, int) et add(float, float) ?

26 Un C amélioré L’édition des liens
Le C++ crée donc des symboles spéciaux qui représentent la signature des fonctions au lieu des noms de fonctions. Cela s ‘appelle le name « mangling». L ‘opération inverse, passer du nom de la signature au nom de la fonction s ‘appelle le name « demangling». Chaque compilateur peut avoir sa propre convention du mangling/demangling. On ne peut pas toujours linker un code compilé avec un compilateur C++ avec un code compilé avec un autre compilateur C++ sur une même machine. On ne peut debugguer un code C++ que si le debugger C++ sait faire le demangling inverse du compilateur utilisé pour fabriquer le code de l’application. Il est impossible de linker simplement du C++ avec du C ou l’inverse.

27 Un C amélioré L’édition des liens
Conscients de ces problèmes, les concepteurs du C++ ont prévu l’outillage permettant d’interfacer simplement du C++ avec du C. Header C++ extern "C" { int add_int_C(int, int); float add_float_C(float, float); } Fichier C++ Le code de add_int_C et add_float_C se trouve dans un fichier C. int i = add_int_C(1, 2); float f = add_float_C(1.0, 2.0);

28 Un C amélioré Allocation dynamique
L’allocation dynamique fait partie intégrante du C++. Ce ne sont plus des Fonctions qu’il faut savoir utiliser comme malloc(), realloc, fre()… Deux opérateurs sont prévus: new et delete. struct Toto { int i; float f; }; typedef Toto* TotoPtr; TotoPtr t = new Toto; // équivalent à (TotoPtr) malloc(sizeof(structToto)). ... t->i = 1; t->f = 1.0; delete t; // équivalent à free(t);

29 Un C amélioré Allocation dynamique
L’allocation des tableaux est quasiment identique. Deux opérateurs sont prévus: new [] et delete []. struct Toto { int i; float f; }; typedef Toto* TotoPtr; TotoPtr t = new Toto[10]; ... t[0].i = 1; t[0].f = 1.0; delete [] t;

30 Un C amélioré Allocation dynamique
L’opérateur new[] permet également d’allouer des tableaux à plusieurs dimensions. Pour cela, il suffit de spécifier les tailles des différentes dimensions à la suite du type de donnée des éléments du tableau, exactement comme lorsque l’on crée un tableau statiquement. Toutefois, seule la première dimension du tableau peut être variable, et les dimensions deux et suivantes doivent avoir une taille entière positive et constante. Par exemple, seule la deuxième ligne de l’exemple qui suit est une allocation dynamique de tableau valide : int i=5, j=3; int (*pi1)[3] = new int[i][3]; // Alloue un tableau de i lignes de trois entiers. int (*pi2)[3] = new int[i][j]; // Illégal, j n’est pas constant. Si l’on désire réellement avoir des tableaux dont plusieurs dimensions sont de taille variable, on devra allouer un tableau de pointeurs et, pour chaque ligne de ce tableau, allouer un autre tableau à la main (dans une boucle).

31 Un C amélioré Allocation dynamique
L’opérateur new[] permet également d’allouer des tableaux à plusieurs dimensions. Pour cela, il suffit de spécifier les tailles des différentes dimensions à la suite du type de donnée des éléments du tableau, exactement comme lorsque l’on crée un tableau statiquement. Toutefois, seule la première dimension du tableau peut être variable, et les dimensions deux et suivantes doivent avoir une taille entière positive et constante. Par exemple, seule la deuxième ligne de l’exemple qui suit est une allocation dynamique de tableau valide : int i=5, j=3; int (*pi1)[3] = new int[i][3]; // Alloue un tableau de i lignes de trois entiers. int (*pi2)[3] = new int[i][j]; // Illégal, j n’est pas constant. Si l’on désire réellement avoir des tableaux dont plusieurs dimensions sont de taille variable, on devra allouer un tableau de pointeurs et, pour chaque ligne de ce tableau, allouer un autre tableau à la main (dans une boucle).

32 Un C amélioré Allocation dynamique
Attention, il ne faut pas mélanger new/delete avec malloc/free. Il ne faut pas mélanger non plus new/delete et new []/delete []. Sinon, le comportement du programme n’est plus garanti. Il est important donc d’utiliser l’opérateur delete[] avec les pointeurs renvoyés par l’opérateur new[] et l’opérateur delete avec les pointeurs renvoyés par new. De plus, on ne devra pas non plus mélanger les mécanismes d’allocation mémoire du C et du C++ (utiliser delete sur un pointeur renvoyé par malloc par exemple). En effet, le compilateur peut allouer une quantité de mémoire supérieure à celle demandée par le programme afin de stocker des données qui lui permettent de gérer la mémoire. Ces données peuvent être interprétées différemment pour chacune des méthodes d’allocation, si bien qu’une utilisation erronée peut entraîner soit la perte des blocs de mémoire, soit une erreur, soit un plantage.

33 Un C amélioré Allocation dynamique
L’opérateur new[] alloue la mémoire et crée les objets dans l’ordre croissant des adresses. Inversement, l’opérateur delete[] détruit les objets du tableau dans l’ordre décroissant des adresses avant de libérer la mémoire. La manière dont les objets sont construits et détruits par les opérateurs new et new[] dépend de leur nature. S’il s’agit de types de base du langage ou de structures simples, aucune initialisation particulière n’est faite. La valeur des objets ainsi créés est donc indéfinie, et il faudra réaliser l’initialisation soi-même. Si, en revanche, les objets créés sont des instances de classes C++, le constructeur de ces classes sera automatiquement appelé lors de leur initialisation. C’est pour cette raison que l’on devra, de manière générale, préférer les opérateurs C++ d’allocation et de désallocation de la mémoire aux fonctions malloc et free du C. Ces opérateurs ont de plus l’avantage de permettre un meilleur contrôle des types de données et d’éviter un transtypage. Les notions de classe et de constructeur seront présentées en détail dans le chapitre traitant de la couche objet du C++.

34 Un C amélioré Allocation dynamique
L’opérateur new[] alloue la mémoire et crée les objets dans l’ordre croissant des adresses. Inversement, l’opérateur delete[] détruit les objets du tableau dans l’ordre décroissant des adresses avant de libérer la mémoire. La manière dont les objets sont construits et détruits par les opérateurs new et new[] dépend de leur nature. S’il s’agit de types de base du langage ou de structures simples, aucune initialisation particulière n’est faite. La valeur des objets ainsi créés est donc indéfinie, et il faudra réaliser l’initialisation soi-même. Si, en revanche, les objets créés sont des instances de classes C++, le constructeur de ces classes sera automatiquement appelé lors de leur initialisation. C’est pour cette raison que l’on devra, de manière générale, préférer les opérateurs C++ d’allocation et de désallocation de la mémoire aux fonctions malloc et free du C. Ces opérateurs ont de plus l’avantage de permettre un meilleur contrôle des types de données et d’éviter un transtypage. Les notions de classe et de constructeur seront présentées en détail dans le chapitre traitant de la couche objet du C++.

35 Un C amélioré Allocation dynamique
Lorsqu’il n’y a pas assez de mémoire disponible, les opérateurs new et new[] peuvent se comporter de deux manières selon l’implémentation. Le comportement le plus répandu est de renvoyer un pointeur nul. Cependant, la norme C++ indique un comportement différent : si l’opérateur new manque de mémoire, il doit appeler un gestionnaire d’erreur. Ce gestionnaire ne prend aucun paramètre et ne renvoie rien. Selon le comportement de ce gestionnaire d’erreur, plusieurs actions peuvent être faites : soit ce gestionnaire peut corriger l’erreur d’allocation et rendre la main à l’opérateur new ( le programme n’est donc pas terminé), qui effectue une nouvelle tentative pour allouer la mémoire demandée ; soit il ne peut rien faire. Dans ce cas, il peut mettre fin à l’exécution du programme ou lancer une exception std::bad_alloc, qui remonte alors jusqu’à la fonction appelant l’opérateur new. C’est le comportement du gestionnaire installé par défaut dans les implémentations conformes à la norme.

36 Un C amélioré Allocation dynamique
L’opérateur new est donc susceptible de lancer une exception std::bad_alloc. Voir la partie qui traite de la gestion des exceptions pour plus de détails à ce sujet. Il est possible de remplacer le gestionnaire d’erreur appelé par l’opérateur new à l’aide de la fonction std::set_new_handler, déclarée dans le fichier d’en-tête new. Cette fonction attend en paramètre un pointeur sur une fonction qui ne prend aucun paramètre et ne renvoie rien. Elle renvoie l’adresse du gestionnaire d’erreur précédent. La fonction std::set_new_handler et la classe std::bad_alloc font partie de la bibliothèque standard C++. Comme leurs noms l’indiquent, ils sont déclarés dans l’espace de nommage std::, qui est réservé pour les fonctions et les classes de la bibliothèque standard. Voyez aussi le Chapitre 11 pour plus de détails sur les espaces de nommages. Si vous ne désirez pas utiliser les mécanismes des espaces de nommage, vous devrez inclure le fichier d’en-tête new.h au lieu de new. Attendez vous à ce qu’un jour, tous les compilateurs C++ lancent une exception en cas de manque de mémoire lors de l’appel à l’opérateur new, car c’est ce qu’impose la norme. Si vous ne désirez pas avoir à gérer les exceptions dans votre programme et continuer à recevoir un pointeur nul en cas de manque de mémoire, vous pouvez fournir un deuxième paramètre de type std::nothrow_t à l’opérateur new. La bibliothèque standard définit l’objet constant std::nothrow à cet usage.

37 Un C amélioré Allocation dynamique
Les opérateurs delete et delete[] peuvent parfaitement être appelés avec un pointeur nul en paramètre. Dans ce cas, ils ne font rien et redonnent la main immédiatement à l’appelant. Il n’est donc pas nécessaire de tester la non nullité des pointeurs sur les objets que l’on désire détruire avant d’appeler les opérateurs delete et delete[].

38 Un C amélioré Fonctions génériques
La générécité est le fait que el code d’une fonction soit indépendant du type des objets qu’elle manipule. template <liste de paramètres> fonction Avec T = int, ça donne inline T add (T a , T b){ return a+b; } Template <class T> inline T add (T a , T b){ return a+b; }

39 Un C amélioré Fonctions génériques Template <class T>
T max (T t[] , int sz){ T mx = t[0]; for(int i = 1; i < sz; i++) mx = max<T>(mx, t[i]); return mx; } Template <class T> inline T max (T x , T y){ return (x>y ? x:y); } int tab_int[] = {2, 4, 8, 16, 1, 5, 9, 17}; float tab_float [] = {1.0, 3.3, 4.4, 2.2, 10.10, 1.3}; cout << max<int> (tab_int, int (sizeof(tab_int)/sizeof(int))); cout << max<float> (tab_float, int (sizeof(tab_float)/sizeof(float)));

40 Un C amélioré Fonctions génériques
On peut aussi appeler explicitement les types du template lors de l’appel de la fonction. max(1,2); est équivalent à Max<int> (1,2);

41 Un C amélioré Fonctions génériques
Exercice. Avec les templates, reinterpret_cast et le passage de paramètres Par référence, écrivez une fonction générique qui recopie octet par octet le contenu d’un opérande dans un autre (une sorte de strcpy() en C++). Solution. template <class TS, class TD> void memcpy(TS src, TD &dst) { int sz = sizeof(src); if( sz > sizeof(dst)) sz = sizeof(dst); char *src2 = reinterpret_cast<char*>(&src); char *dst2 = reinterpret_cast<char*>(&dst); for (int i=0; i < sz; i++) dst[i] = src[i]; }

42 Un C amélioré Fonctions génériques
Exercice. Réutilisez la fonction memcpy() dans une nouvelle fonction tabcpy() dont le but est de copier un tableau dans un autre de même taille. Solution. template <class E> void tabcpy(E *src, E *dst, int n) { for (int i=0; i < n; i++) memcpy<E,E> (src[i], dst[i] ); }

43 Un C amélioré Les entrées/sorties Le concept de flots d’octets
C++ Description C iostream bibliothèque C++ des flots stdio.h istream flot d ‘entrée – ostream flot de sortie << opération de sortie printf >> opération d ‘entrée scanf cin flot entrée standard stdin cout flot de sortie standard stdout cerr flot de sortie des erreurs stderr clog flot desortie des erreurs - endl fin deligne ” \n ‘

44 Un C amélioré Les entrées/sorties Le concept de flots d’octets
Les opérateurs << et >> sont génériques. On peut mélanger les types. short s = 1; int i = 2; long l = 3; float f= 4.5; double d = 6.7; cout<<"s= "<<s<<"i= "<<i…"d= "<<d<<endl; Il n ‘y a plus de chaîne de format à la « printf».

45 Un C amélioré Les entrées/sorties Le concept de flots d’octets
Les opérateurs << et >> sont génériques. Ils sont définis sur les types: bool, short, int, long float, double char, char* On doit les redéfinir soi-même pour les types que l ‘on crée si on veut les afficher.

46 Un C amélioré Les entrées/sorties Le concept de flots d’octets
On dispose de manipulateurs spéciaux sur les flots C++ C syntaxe fait quoi flush fflush cout << flush; vide le tampon endl \n + fflush cout << endl; fin de ligne hex cout << hex; hexa oct cout << oct; octal dec cout << dec; décimal ws cin >> ws; élimine blancs

47 Un C amélioré Les entrées/sorties Le concept de flots d’octets
Il existe des manipulateurs ayant des paramètres, ils sont Définis dans la bibliothèque « iomanip » #include <iomanip> setw(n) en sortie spécifie la largeur du champ en caractères cadrage à droite : int i = 777; cout << setw(10) << i; setw(n) en entrée spécifie le nombre max de caractères lus char t[10] cin << setw(10) << t;

48 Un C amélioré Les entrées/sorties Le concept de flots d’octets
#include <iomanip> setprecision(n) spécifie le nombre de chiffres significatifs pour les nombres flottants. Par défaut, le nombre de chiffres et 6 (partie entière + décimale). float f= ; cout << f<< endl; cout << setprecision(9) << f<< endl;

49 Un C amélioré Les entrées/sorties Le concept de flots d’octets
#include <iomanip> setfill(” caractère‘) spécifie le caractère de remplissage pour setw(n). Par défaut c‘est un espace « blanc» int i= 777; cout << setfill(” . ‘); cout << setw(10) << i;

50 Un C amélioré Les entrées/sorties Le concept de flots d’octets
L ‘opérateur >> est évalué à vrai tant que la fin de fichier n ‘est pas atteinte. Voici « cat » (avec un seul fichier) en C++ int main() { char c; while(cin >> c) cout << c; return 0; }

51 Un C amélioré Les entrées/sorties Le concept de flots d’octets
Si vous consultez le résultat, vous devriez avoir une surprise. La recopies s‘est faite sans les séparateurs (blanc, tab, return, line feed, …). Essayez le programme suivant. int main() { char c; while(cin.get(c)) cout << c; return 0; }

52 La fonction symétrique de get() est put()
Un C amélioré Les entrées/sorties Le concept de flots d’octets La fonction symétrique de get() est put() int main() { char c; while(cin.get(c)) cout.put(c); return 0; }

53 Un C amélioré Les entrées/sorties Le concept de flots d’octets
La fonction getline() permet de lire une ligne complète, séparateurs compris. const int MAX = 10; int main() { char t[MAX]; while(cin.getline(t, MAX, ‘\n‘)) cout << t << endl; return 0; }

54 Un C amélioré Les entrées/sorties #include <iostream>
int const MAX = 10; // eof+bad+good+fail+clear test int main() { char line[MAX]; for (;;){ cin.getline(line, MAX, '\n'); if (cin.fail()) cout << " fail "; if (cin.bad()) cout << " bad "; if (cin.good()) cout << " good "; if (cin.eof()) break; if (!cin.good()) cin.clear(); cout << line << endl; } cout << "eof" << endl; return 0; Le concept de flots d’octets Fonctions de flots eof() fin de fichier fail() erreur bad() problème grave good() pas de problème clear() annule les problèmes

55 Un C amélioré Les entrées/sorties Autres fonctions de flots
putback(char) « pousse» un octet qui sera lu par get() peek() lit l ‘octet sans le retirer du flot seekg() positionne le pointeur de get() seekp() positionnelepointeur de put() tellg() retourne le pointeur de get() tellp() retourne le pointeur de put()

56 Un C amélioré Les entrées/sorties
On peut lire les flots dans un fichier open() close() Il y a de nouvelles fonctions de flots #include <ifstream> #include <ofstream> #include <fstream> Il y a de nouveaux includes

57 flot.open("toto", ios::out|ios::trunc); f= fopen("toto", "w");
Un C amélioré Les entrées/sorties Flots et fichiers : fopen() modes C++ signification ios::in read ios::write write ios::trunc tronque ios::app append ios::binary binaire En C flot.open("toto", ios::out|ios::trunc); f= fopen("toto", "w");

58 Un C amélioré Les entrées/sorties Flots et fichiers : fopen()
Un fichier est automatiquement ouvert à la création d ‘une variable si on utilise la syntaxe suivante: ofstream ofs ("toto.out", ios::out|ios::trunc); ifstream ifs ("toto.in", ios::in);

59 Un C amélioré Les entrées/sorties Flots et fichiers : fclose()
flot.fclose(); C++ est « dynamique»: lorsqu‘une variable de flot n ‘existe plus, le fichier éventuellement attaché au flot est automatiquement fermé.

60 Un C amélioré Les entrées/sorties Différence entre le C et le C++
- commentaires // -nouveaux mots réservés -les caractères sont vraiment des char, plus des int -une chaîne de caractères est un tableau de « const char » -la structure définit aussi le type de même nom -un idf const et pas extern ne peut être utilisé ailleurs -on ne peut convertir un void* vers un pointeur sans cast -seuls les pointeurs sur des non const et non volatile peuvent être convertis implicitement vers des void* -déclaration implicite de fonctions est interdite -fonctions avec type de retour nécessite return -extern et static sont réserves à des objets ou des fonctions -toute constante doit être initialisée -pas de type implicite int -on ne mélange pas les enum entre eux ni avec des int

61 Nouveaux types Types abstraits Concept de classe
Constructeur -destructeur Imbrication de classes Données membres de type classe « friend » Ordred ‘appel des const/destr Classes génériques Surdéfinition d ‘opérateurs Données membres statiques Fonctions membres statiques Opérateur de portée Conversion de types Portée des identificateurs Espaces de nommage Constantes « non constantes »

62 Nouveaux types Types abstraits
Un type abstrait de données est un ensemble de valeurs ou un ensemble d ‘objets (informations organisées) ainsi que les opérations permises sur ces valeurs. Exemple. Les entiers munis des quatre opérations arithmétiques. L ‘utilisateur ne connaît pas la représentation interne. La fonctionnalité est plus importante que la représentation.

63 Nouveaux types Concept de classe Une classe est un ensemble de:
données ayant un lien entre elles (comme struct) « données membres » + méthodes servant à manipuler les données membres « fonctions membres » C’est la structure de base des langages orientés objet.

64 Nouveaux types Concept de classe
Une classe est un ensemble de données et de méthodes privées (partie invisible, masquée) ou public (partie visible, accessible à l’utilisateur)

65 Nouveaux types Concept de classe Les méthodes sont de quatre types :
les constructeurs (initialisation correcte) destructeur (fin de vie correcte) les accesseurs (lecture seulement) les modificateurs (lecture+écriture)

66 Nouveaux types Concept de classe Syntaxe de la définition d’une classe
class <class name> {<data + functions>} <vars> ; La liste de données et de fonctions est marquée par les mots clés « public» et « private» qui dénotent respectivement quelles sont les données et les fonctions « publiques » ou« privées ». Par défaut, en l ‘absence de ces mots clés, les données et les fonctions sont « privées ».

67 Nouveaux types Concept de classe constructeur
class FigureGeometrique { public: FigureGeometrique(); ~FigureGeometrique(); inline double surface() const; inline const char *nom() const; void surface (double); private: const char * nom; double surface; } destructeur accesseurs modificateur

68 Nouveaux types Concept de classe
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 de la 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;

69 Nouveaux types Concept de classe
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; };

70 Nouveaux types Concept de classe
Les objets sont les instances de classes. FigureGeometriqueX; // déclaration X.surface(2.0); // écriture double d = X.surface(); // lecture cout << d << endl; // affichage

71 Nouveaux types Constructeurs class X { public : X();
}; - portent le même nom que la classe n ‘ont pas de type de retour sont invoqués 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 :-)

72 Nouveaux types Constructeurs Il peut y avoir plusieurs constructeurs.
class X { public: X() X(const X&); X& operator = (const X&); }; Constructeur par défaut Constructeur de copie Surdéfinition de = X a; //défaut X b = a; // copie X c(a); //copie X d = X(a); //double copie d = a //affectation

73 Nouveaux types Constructeurs 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)

74 Nouveaux types Constructeurs
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&) {} } ;

75 Nouveaux types Constructeurs Pourquoi 3 constructeurs ?
Défaut = initialisation Copie = recopie à partie d’un modèle Affectation = 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;

76 Nouveaux types Constructeurs
Pour désigner l’objet en cours de construction, il y a la variable « this » qui est un pointeur sur un objet de la classe du constructeur. X& X::operator=(const X& arg) { if(this == &arg) return *this; return *this; }

77 Nouveaux types Destructeur class X { public : ~X();
}; - 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

78 Nouveaux types Destructeur
Si le programmeur ne définit pas le destructeur, le compilateur le fait automatiquement pour lui, cependant, et comme les constructeurs, ile faut le spécifier à « vide » lors de la déclaration de la classe. class X { public: ~X() {} } ;

79 Nouveaux types 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() {...}; } ;

80 Nouveaux types 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;

81 Nouveaux types Imbrication de classes
On peut déclarer une classe dans le corps d’une autre classe class X { public: X(); private: class Y {...}; ... };

82 Nouveaux types Données membres
Les données membres d’une classe peuvent être des objets, c’est-à-dire des instances d’une autre classe. class Y {...}; class X { public: X(); private: Y y; ... };

83 Nouveaux types « friend »
Une classe peut être « amie » d’une autre classe et avoir accès à ses données et méthodes privées. 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; };

84 Nouveaux types 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.

85 Nouveaux types Ordre d’Appel des constructeurs et destructeur Exercice
class X{ public : X() { cout << ‘x’;} ~X() {cout << ‘X’;} class Y y; class Z z; }; class Z{ public : Z() { cout << ‘z’;} ~Z() {cout << ‘Z’;} }; int main() { X x; cout << endl; return 0; }; class Y{ public : Y() { cout << ‘y’;} ~Y() {cout << ‘Y’;} };

86 Nouveaux types Classes génériques
Une classe générique est une classe avec un template. Même principe que les fonctions génériques. Template <class 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;

87 Nouveaux types Surcharges des opérateurs
Les opérateurs que l’on peut surcharger sont : + - * / % ^ & | ~ ! = < > <= >= << >> == != && || += -= /= *= ^= &= |= <<= >>= [] () -> new delete new[] delete[] Les opérateurs quel ‘on nepeut pas surcharger sont: :: . ?: sizeof

88 Nouveaux types Surcharges des opérateurs On ne peut changer
les règles de précédence l’associativité le nombre d’opérandes On ne peut créer de nouveaux opérateurs

89 Nouveaux types Surcharges des opérateurs
template<class T> class X { public: X& operator+(const X& arg){ X *x = new X(); x->n = n + arg.n; return *x; } T n; }; Exercice: utilisez cette classe pour écrire un programme qui crée un nouvel objet C par « addition » de deux objets A et B.

90 Nouveaux types Surcharges des opérateurs
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; };

91 Nouveaux types Surcharges des opérateurs
ostream& operator<<(ostream& o, const A& a) { o << "i = "<< a.i << " f= "<< a.f<< endl; return 0; } istream& iperator<<(istream& i, const A& a) i >> a.i >> a.f; return i;

92 Nouveaux types Surcharges des opérateurs Exercice
Écrivez un programme dans lequel une classe contenant au moins deux chaînes de 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ées en redéfinissant les opérateurs de flots.

93 Nouveaux types Surcharges des opérateurs
Problèmes des opérateurs ++ et --. Ils peuvent être en préfixe ou en suffixe. Lequel est redéfini ? class X { ... X& operator++();   //préfixe X& operator++(int); //suffixe  …   };  

94 Nouveaux types Surcharges des opérateurs Exercice
É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é.

95 Nouveaux types Données et membres statiques Sorte de variable globale
« locale à la classe » initialisée à 0 par le compilateur si pas initialisée par le programmeur class A { friend class B; public: A() { i =0; f = 0.0; n++;}; ~A() {}; static int n; private : int i; float f; } int A:: n =-1;

96 Nouveaux types Données et membres statiques Fonction/méthode
«de classe » qui seule peut modifier les données 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; } A:: reset();

97 Nouveaux types Fonctions et données statiques Exercice
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.

98 Nouveaux types 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. int X:: i; int Y:: i; int i; const int I = 2; class X { public: static int i; static const int I = 1; }; class Y { static const int I = 3; 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; }

99 Nouveaux types Conversion de type
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 objet X(0) car le constructeur X(int) existe.

100 Nouveaux types Conversion de type
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 objet X(0) car le constructeur X(int) existe.

101 Nouveaux types Conversion de type
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 explicitement En en un objet X(0) avant recopie dans x.

102 Nouveaux types Conversion de type
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);

103 Nouveaux types Conversion de type Exercice
É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 >>.

104 Portée de l’espace de nommage
Nouveaux types Portée des identificateurs Il y en a 5! Portée globale Portée de fichier Portée de bloc Portée de classe Portée de l’espace de nommage

105 Nouveaux types Portée des identificateurs 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 autres Fichiers doivent la déclarer « extern » pour Pouvoir y accéder sans la dupliquer.

106 Nouveaux types Portée des identificateurs 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ême s’ils déclarent une autre variable N ou tente de la qualifier « extern ».

107 Nouveaux types Portée des identificateurs 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.

108 Nouveaux types Portée des identificateurs Portée de bloc
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; } N n’est connu que dans cette zone. C’est-à-dire après sa déclaration et jusqu’à La fermeture du bloc englobant.

109 Nouveaux types Portée des identificateurs 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

110 Dans une fonction membre de la classe
Nouveaux types Portée des identificateurs 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();} };

111 Après l’opérateur « . » appliqué à un objet instance de la classe
Nouveaux types Portée des identificateurs 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;

112 Nouveaux types Portée des identificateurs 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;

113 Après l’opérateur de résolution de portée appliqué à la classe
Nouveaux types Portée des identificateurs 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();

114 Portée d’espace de nommage
Nouveaux types Portée des identificateurs Portée d’espace de nommage Pourquoi ? Lorsque l’on se linke avec une Bibliothèque on réutilise les idfs Qui y sont définis. On ne peut pas Définir d’idf ayant le même nom Que 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> }

115 Portée d’espace de nommage
Nouveaux types Portée des identificateurs Portée d’espace de nommage Comment ? Chaque fournisseur de bibliothèque Doit encapsuler ses déclarations dans Un espace de nommage. Les STL, les librairies standards du C++, Sont dans l’espace de nommage « std ». namespace <idf> { <declarations> }

116 Portée d’espace de nommage
Nouveaux types Portée des identificateurs Portée d’espace de nommage Espace de nommage « anonyme » est équivalent à l’usage de « static » mais sans avoir 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.

117 Portée d’espace de nommage
Nouveaux types Portée des identificateurs 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>

118 Portée d’espace de nommage
Nouveaux types Portée des identificateurs 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;

119 Nouveaux types Constantes non constantes
Ce n’est pas une blague de mauvais goût! Ce sont des membres dits « mutables » Mutable n’est pas compatible avec const et static Mutable signifie « ne sera jamais constant » Permet au programmeur de changer la valeur d’une donnée membre même Si 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;

120 Programmation orienté objet
Avantages de la programmation par objet Héritage Persistance Concept objet avancé en C++: Objets homogènes Classes abstraites Structures hétérogènes Héritage multiple Gestion des exception

121 Programmation orienté objet
Modularité Encapsulation Abstraction Extensibilité 1 classe = 1 module Parties privée et publique des classes Interface de la classe = type abstrait + généricité (templates) Héritage

122 Programmation orienté objet
class X: <mode> Y { } Syntaxe Mode Ancètre Dérivée Private Private Inaccessible Protected Private Public Private Protected Private Inaccessible Protected Protected Public Protected Public Private Inaccessible Protected Protected Public Public public protected private Mode

123 Programmation orienté objet
Héritage « public » class Y : public X { public: Y() { x1 = 0; //public x2 = 0; //protected x3 = 0; //NON } }; Y y; Cout << y.x1 << endl; Cout << y.x2 << endl; //NON Cout << y.x3 << endl; //NON class X{ public: int x1; protected: int x2; private: int x3; }; X x; cout << x.x1 << endl; Cout << x.x2 << endl; //NON Cout << x.x3 << endl; //NON

124 Programmation orienté objet
Héritage « protected » class X{ public: int x1; protected: int x2; private: int x3; }; class Y : protected X { public: Y() { x1 = 0; //protected x2 = 0; //protected x3 = 0; //NON } }; Y y; Cout << y.x1 << endl; //NON Cout << y.x2 << endl; //NON Cout << y.x3 << endl; //NON X x; cout << x.x1 << endl; Cout << x.x2 << endl; //NON Cout << x.x3 << endl; //NON

125 Programmation orienté objet
Héritage « private » class X{ public: int x1; protected: int x2; private: int x3; }; class Y : private X { public: Y() { x1 = 0; //private x2 = 0; //private x3 = 0; //NON } }; Y y; Cout << y.x1 << endl; //NON Cout << y.x2 << endl; //NON Cout << y.x3 << endl; //NON X x; cout << x.x1 << endl; Cout << x.x2 << endl; //NON Cout << x.x3 << endl; //NON

126 Programmation orienté objet
Construction des objets Nouvelles données membres Données membres classe ancêtre Un objet d’une classe dérivée contient Redéfinition d’anciennes données membres

127 Programmation orienté objet
Contenu de la classe dérivée Fonctions membres classe ancêtre Nouvelles +redéfinition fonctions membres Pas les « friend » Une classe dérivée contient Nouveaux constructeurs Nouveau destructeur

128 Programmation orienté objet
Construction des objets class X{ public: int x1; void a() {…} protected: int x2; private: int x3; }; class Y : public X { public: int x1; //redéfini int y; //nouveau void a() {…} // redéfini void b() {…} // nouveau int a() {…} // nouveau };

129 Programmation orienté objet
Construction des objets Si on veut utiliser une fonction de la classe ancêtre alors qu’elle a été redéfinie dans la classe dérivée, il faut utiliser l’opérateur de portée « :: » class X{ public: void a() {…} }; class Y : public X { public: void a() {…} // redéfini void b() { X::a();// autre classe a(); //local } };

130 Programmation orienté objet
Construction des objets Lors de la construction d’un objet des constructeurs de toute la hiérarchie Des classes sont appelées dans l’ordre de la hiérarchie « top-down ». class Z : public Y { public: Z() { cout << ‘z’;} }; class X{ public: X() {cout << ‘x’;} }; int main() { Z z; cout << endl; } class Y : public X { public: Y() { cout << ‘y’;} };

131 Programmation orienté objet
Construction des objets S’il n’y a pas de constructeur par défaut spécifié par le programmeur, Il faut alors une séquence d’initialisation!!! class Y : public X { public: int j; Y(int n): X(n) { j = n;} }; class X{ public: int i; X(int n) { i = n;} }; class Z : public Y { public: int k; Z(int n): Y(n) { k = n;} };

132 Programmation orienté objet
Destruction des objets Lors de la destruction d’un objet, les destructeurs de toute la hiérarchie des classes sont appelées dans L’ordre de la hiérarchie « bottom-up » class Z : public Y { public: ~Z() {cout << ‘Z’;} }; class X{ public: ~X() { cout << ‘X’;} }; int main() { Z z; cout << endl; } class Y : public X { public: ~Y() {cout << ‘Y’;} };

133 Programmation orienté objet
Liaison dynamique C’est la possibilité de ne lier qu’au moment de l’exécution la méthode à invoquer (pas possible pour les constructeurs). class X{ public: virtual void a() { < cout << ‘X’ << endl;} }; X x; Y y; x.a(); y.a(); x = y; x.a();//? X *x = new X(); Y *y = new Y(); X->a(); Y->a(); x = y; X->a();//? class Y : public X { public: virtual void a() { cout << ‘Y’ << endl;} };

134 Programmation orienté objet
Liaison dynamique C’est la possibilité de ne lier qu’au moment de l’exécution la méthode à invoquer (pas possible pour les constructeurs). class X{ public: virtual void a() { < cout << ‘X’ << endl;} }; X x; Y y; x.a(); y.a(); x = y; x.a();//? X *x = new X(); Y *y = new Y(); X->a(); Y->a(); x = y; X->a();//? class Y : public X { public: virtual void a() { cout << ‘Y’ << endl;} };

135 Programmation orienté objet
Liaison dynamique Que se passe-t-il sans « virtual » ? class X{ public: void a() { < cout << ‘X’ << endl;} }; X *x = new X(); Y *y = new Y(); X->a(); Y->a(); x = y; X->a();//? class Y : public X { public: void a() { cout << ‘Y’ << endl;} };

136 Programmation orienté objet
Classe abstraite C’est une classe « mère » dans laquelle au moins une méthode est virtuelle et pure. Virtuelle = utilise le mot clé « virtual » Pure = pas d’implémentation de la méthode + «  = 0 » C’est similaire au concept d’interface en Java. Attention: il n’est pas permis de créer d’objet instances d’une classe abstraire. Inutile de spécifier les constructeurs et le destructeur.

137 Programmation orienté objet
Classe abstraite Classe abstraire class X{ public: virtual void a() = 0; virtual void b() = 0; }; Classe non abstraire virtual est facultatif class Y : public X { public: virtual void a() { cout << ‘a’ << endl;} virtual void b() { cout << ‘b’ << endl;} };

138 Programmation orienté objet
Héritage multiple class X{ public: int i; X(int n) { i = n;} void a() {…}; }; class T: public X, public Y, public Z { public: int i; //redéfinition de i!! T(): X(0), Y(0), Z(0) { i =0;} void c() { j +=1; i +=1; b(); //pas d’ambiguité //a(); //ambiguité X::a(); Y::a(); } }; class Y { public: int i; Y(int n) { i=n;} void a() {…} }; class Z { public: int j; Z(int n) { j=n;} void b() {…} };

139 Programmation orienté objet
Héritage multiple class X{ public: int i; X(int n) { i = n;} void a() {…}; }; class T: public Y, public Z { public: int l; T(): X(0), Y(0), Z(0) { l = 0;} void d() { j +=1; k +=1; l +=1; //i +=1; //ambiguité Y::i +=1; Z::i +=1; //a(); //ambiguité Y::a(); Z::a(); } }; class Y: public X { public: int j; Y(int n) { j=n;} void b() {…} }; class Z: public X { public: int k; Z(int n) { k=n;} void c() {…} };

140 Programmation orienté objet
Héritage multiple class X{ public: int i; X(int n) { i = n;} void a() {…}; }; class T: virtual public Y, virtual public Z { public: int l; T(): X(0), Y(0), Z(0) { l = 0;} void d() { j +=1; k +=1; l +=1; i +=1; a(); } }; class Y: virtual public X { public: int j; Y(int n) { j=n;} void b() {…} }; class Z: virtual public X { public: int k; Z(int n) { k=n;} void c() {…} };

141 Programmation orienté objet
Les exceptions Une fonction en face d’un problème qu’elle ne sait pas résoudre lance (throw) Une exception en espérant qu’une fonction appelante à un niveau supérieur Puisse l’intercepter (catch). Cas archi-classique de la division par 0 : le problème. class X{ public: int i; X(int n) { i = n;} void div(int n) {i /=n;} };

142 Programmation orienté objet
Les exceptions Cas archi-classique de la division par 0 : la solution en C++. class X{ public: int i; X(int n) { i = n;} void div(int n) { if (n==0) throw Div0(); else i /=n; } private: }; class Div0{};

143 Programmation orienté objet
Les exceptions Cas archi-classique de la division par 0 : sa mise en œuvre. int main{ X x(1); try { x.div(0); cout << "Ok" << endl; } catch(Div0){ cout << "Erreur" << endl; return 0; };

144 Programmation orienté objet
Les exceptions Une classe peut renvoyer plusieurs exceptions. class X{ public: int i; X(int n) { i = n;} void div(int n) { if (n==0) throw E1(); else (if n<0) throw E2(); else i /=n; } private: }; Class E1 {}; Class E2 {}; // ou Enum {E1, E2} Exception;

145 Programmation orienté objet
Les exceptions Cas archi-classique de la division par 0 : sa mise en œuvre. int main{ X x(1); try { x.div(0); // x.div(-1); cout <<   "Ok" << endl; }catch(E1){ cout << "Erreur E1" << endl; }catch(E2){ cout <<  "Erreur E2" << endl; } return 0; };


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

Présentations similaires


Annonces Google