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

Présentations similaires


Présentation au sujet: "Structures de données IFT-10541 Abder Alikacem Introduction au langage C++ Département d’informatique et de génie logiciel Édition Septembre 2009."— Transcription de la présentation:

1 Structures de données IFT Abder Alikacem Introduction au langage C++ Département d’informatique et de génie logiciel Édition Septembre 2009

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 int main(){ printf("hello world\n"); return 0; } #include int main(){ cout << "hello world" << endl; return 0; }

6 Un C amélioré Commentaires 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 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

15 Un C amélioré  surdéfinitions de fonctions double add(double a, double b){ return a + b; } int add(int a, int b){ return a + b; } int i = add(1, 2); double d = add(1.0, 2.0); (int, add, int, int) (double, add, double, double) 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

16 Un C amélioré  Arguments par défaut double add(double a, double b = 2.0){ return a + b; } double d = add(1.0, 2.0); double dd = add(1.0); 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.

17 Un C amélioré  Fonctions « en ligne » inline double add(double a, double b){ return a + b; } 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. 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 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); cout << SUM << endl; En C++, on peut passer par référence sans avoir à manipuler l’adresse explicitement en utilisant un synonyme d’une variable.

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 Un C amélioré  Conversion de types int i; long l; l = (long) i; Les conversions explicites (type) expression Comme en C a) int i; long l; l = long(i); (type) expression notation fonctionnelle b) #include 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 (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 a; // OK

22 Un C amélioré  Conversion de types Les conversions explicites Le « haut de gamme » de la conversion … reinterpret_cast (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 (i);

23 Un C amélioré  Conversion de types Les conversions explicites Le « haut de gamme » de la conversion … dynamic_cast (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() { int i; 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. extern "C" { int add_int_C(int, int); float add_float_C(float, float); } int i = add_int_C(1, 2); float f = add_float_C(1.0, 2.0); Le code de add_int_C et add_float_C se trouve dans un fichier C. Header C++ Fichier C++

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 fonction Template inline T add (T a, T b){ return a+b; } Avec T = int, ça donne inline T add (T a, T b){ return a+b; }

39 Un C amélioré  Fonctions génériques Template inline T max (T x, T y){ return (x>y ? x:y); } Template T max (T t[], int sz){ T mx = t[0]; for(int i = 1; i < sz; i++) mx = max (mx, t[i]); return mx; } 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 (tab_int, int (sizeof(tab_int)/sizeof(int))); cout (tab_float, int (sizeof(tab_float)/sizeof(float)));

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

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 void memcpy(TS src, TD &dst) { int sz = sizeof(src); if( sz > sizeof(dst)) sz = sizeof(dst); char *src2 = reinterpret_cast (&src); char *dst2 = reinterpret_cast (&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 void tabcpy(E *src, E *dst, int n) { for (int i=0; i < n; i++) memcpy (src[i], dst[i] ); }

43 Un C amélioré  Les entrées/sorties 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 desortiedes erreurs - endl fin deligne ” \n ‘ C++DescriptionC Le concept de flots d’octets

44 Un C amélioré  Les entrées/sorties Les opérateurs > 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= "<

45 Un C amélioré  Les entrées/sorties Les opérateurs > 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. Le concept de flots d’octets

46 Un C amélioré  Les entrées/sorties On dispose de manipulateurs spéciaux sur les flots Le concept de flots d’octets C++Csyntaxefait 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 Il existe des manipulateurs ayant des paramètres, ils sont Définis dans la bibliothèque « iomanip » Le concept de flots d’octets #include 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 setprecision(n) spécifiele 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 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 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 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 #include 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; }

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 Il y a de nouvelles fonctions de flots open() close() Il y a de nouveaux includes #include

57 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 flot.open("toto", ios::out|ios::trunc); f= fopen("toto", "w"); En C

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 { } ; 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 class FigureGeometrique { public: FigureGeometrique(); ~FigureGeometrique(); inline double surface() const; inline const char *nom() const; void surface (double); private: const char * nom; double surface; } constructeur destructeur accesseurs modificateur

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 :: 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  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 Nouveaux types

71  Constructeurs - 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 :-) class X { public : X(); … };

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 - 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 class X { public : ~X(); … };

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 = ⅈ return ptr; } const X x; const int i = 20; cout << *(x.int_ptr(i)) << endl;

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

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

83 Nouveaux types  « friend » class B{ public:B() {a = new A();}; ~B() {}; private: A *a; void reinit_a() { a->i = 0; a->f= 0.0; }; Une classe peut être « amie » d’une autre classe et avoir accès à ses données et méthodes privées. 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 Y{ public : Y() { cout << ‘y’;} ~Y() {cout << ‘Y’;} }; class Z{ public : Z() { cout << ‘z’;} ~Z() {cout << ‘Z’;} }; int main() { X x; cout << endl; return 0; };

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 Nb{ public : T a, b; T add (){ return a+b}; }; Nb 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 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 > 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 É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. Exercice

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

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

96 Nouveaux types  Données et membres statiques class A { friend class B; public: A() { i =0; f = 0.0; n++;}; ~A() {}; static void reset { n = 0;} private: int i; float f; static int n; } Fonction/méthode «de classe » qui seule peut modifier les données membres statiques A:: reset();

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

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. class X { public: static int i; static const int I = 1; }; class Y { public: static int i; static const int I = 3; }; int X:: i; int Y:: i; int i; const int I = 2; int main(){ int i; const int I =4; i = I; ::i = ::I; X::i = X::I; Y::i = Y::I; cout << i << ::i; cout << X::i << Y::i; cout << endl; return 0; }

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 () 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 É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 >. Exercice

104 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 { … { … static int N; … } … } N n’est connu que dans cette zone. C’est-à-dire après sa déclaration et jusqu’à La fermeture du bloc englobant. L’allocation de mémoire est faite statiquement à la compilation, initialisation à 0 (comme toutes les variables globales non initialisées en C).

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 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 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 a() << endl;

113 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 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 { }

115 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 { }

116 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 { } 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 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 :: idf « using »using namespace

118 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 { namespace tutu {…} } namespace titi = toto::tutu;

119 Nouveaux types  Constantes non constantes 1.Ce n’est pas une blague de mauvais goût! 2.Ce sont des membres dits « mutables » 3.Mutable n’est pas compatible avec const et static 4.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 abstraitesStructures hétérogènes Héritage multipleGestion des exception

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

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

123 Programmation orienté objet 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 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  Héritage « public »

124 Programmation orienté objet 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  Héritage « protected » 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

125 Programmation orienté objet 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  Héritage « private » 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

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

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

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 class X{ public: void a() {…} }; class Y : public X { public: void a() {…} // redéfini void b() { X::a();// autre classe a(); //local } }; 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 « :: »

130 Programmation orienté objet  Construction des objets class X{ public: X() {cout << ‘x’;} }; class Y : public X { public: Y() { cout << ‘y’;} }; 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’;} }; int main() { Z z; cout << endl; }

131 Programmation orienté objet  Construction des objets class X{ public: int i; X(int n) { i = n;} }; class Y : public X { public: int j; Y(int n): X(n) { j = n;} }; 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 Z : public Y { public: int k; Z(int n): Y(n) { k = n;} };

132 Programmation orienté objet  Destruction des objets class X{ public: ~X() { cout << ‘X’;} }; class Y : public X { public: ~Y() {cout << ‘Y’;} }; 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’;} }; int main() { Z z; cout << endl; }

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

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

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

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 class X{ public: virtual void a() = 0; virtual void b() = 0; … }; class Y : public X { public: virtual void a() { cout << ‘a’ << endl;} virtual void b() { cout << ‘b’ << endl;} }; Classe abstraire Classe non abstraire virtual est facultatif

138 Programmation orienté objet  Héritage multiple class X{ public: int i; X(int n) { i = n;} void 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() {…} }; 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(); } };

139 Programmation orienté objet  Héritage multiple class X{ public: int i; X(int n) { i = n;} void 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() {…} }; 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(); } };

140 Programmation orienté objet  Héritage multiple class X{ public: int i; X(int n) { i = n;} void 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() {…} }; 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(); } };

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: int i; }; 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: int i; }; 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 Abder Alikacem Introduction au langage C++ Département d’informatique et de génie logiciel Édition Septembre 2009."

Présentations similaires


Annonces Google