|
Retrouvez aussi tous les meilleurs liens du net... ici
Telechargez ici Eclipse, logiciel tres puissant pour coder ; De nombreux plugs-in sont disponibles. |
C++ - La notion d'objet
|
Théorie: Un objet est une représentation informatique d'une entité ou d'un concept réel. Cette notion se rapproche de celle d'une structure: c'est un agrégat de différents types représentant une entité réelle. Cependant, à la différence des structures, les objets apportent le masquage de l'information: c'est "l'encapsulation". Toutes les informations contenues dans l'objet ne sont pas directement accessibles. C'est en quelque sorte l'idée de la boîte noire. Afin d'obtenir une information, il faut en faire la demande auprès de l'objet par l'appel à une fonction de l'interface objet / monde extérieur, c'est à dire une méthode. Cette conception offre une plus grande sécurité d'utilisation par rapport aux structures et permet des changements dans les objets sans que l'utilisateur - programmeur ou programme - soit lésé puisque l'interface reste la même. Pratique: La définition du contenu (données) et du comportement (fonctions ou méthodes) d'un objet se fait à l'aide du mot clé class, équivalent au mot clé struct pour les structures, suivi du nom de la classe d'objets et de ses propriétés. Les propriétés sont soit déclarées public , auquel cas elles sont accessibles à tous, soit déclarées protected ou private , auquel cas elles ne sont accessibles qu'aux fonctions de la classe (masquage de l'information). Une fois que la définition de la classe est terminée, des objets de ce nouveau type peuvent être créés. Exemple: class exemple { public: // Déclaration de la partie publique ou interface de la classe private: // déclaration de la partie masquée de la classe }; |
C++ - Les FLots
|
Théorie: Les entrées / sorties se font en C++ à l'aide des flots (stream). Ces flots peuvent être reliés à l'écran, au clavier, à des fichiers, ou encore à des chaînes de caractères. L'avantage des flots sur les fonctions d'entrées / sorties classiques du C réside dans leur plus grande facilité d'emploi et surtout dans le fait que les opérateurs qui les manipulent peuvent être redéfinis pour de nouveaux types créés par l'utilisateur. Pratique: Les flots sont des objets de deux classes # la classe istream , pour les flots d'entrée # la classe ostream , pour les flots de sortie. Une troisième classe iostream hérite du comportement de ces deux classes et permet donc la création de flots pouvant aussi bien servir à l'entrée qu'à la sortie de données. Les flots par défaut sont cin pour le flot d'entrée standard, cout pour le flot de sortie standard et pour le flot de sortie d'erreurs. Les opérateurs sur les flots les plus importants sont : pour la mise en place d'un objet dans le flot et pour obtenir un objet d'un flot. Il est de plus possible de relier un flot à un fichier (fstream) ou à une chaîne de caractères (strstream). Les flots peuvent être testés afin de déterminer s'ils sont valides ou non. Le principal cas d'invalidité est la tentative de lire un objet d'un mauvais type comme par exemple un float alors qu'un char est attendu. Exemple:: #include<stdlib.h> #include<iostream.h> #include<fstream.h> main() char caractere; ifstream entree("fichier.ext", ios::in); if (!entree) { cout << " Probleme d'ouverture du fichier source " << endl; exit(1); } while (entree >> caractere) cout << caractere; if (entree.bad()) cout << "Erreur au cours de la lecture du fichier " << endl; if (entree.eof()) cout << endl << "Fin de fichier" << endl; |
C++ - Definition des methodes
|
Théorie: Comme nous l'avons vu, il y a dans un objet un masquage d'une partie des informations. Il est donc nécessaire de posséder quelque chose pour les récupérer. C'est le rôle des méthodes. En effet, le masquage de l'information se fait au niveau de la classe, c'est à dire que tout objet ne faisant pas partie de la classe se verra refuser l'accès à la partie privée. Il suffit donc de déclarer une fonction dans la partie publique afin qu'elle puisse être appelée par l'utilisateur et avoir en même temps accès aux données cachées. Certaines méthodes dont obligatoires ou en tout cas fortement conseillées !. Il s'agit des constructeurs, qui portent le même nom que la classe et des destructeurs qui portent le même nom que celui de la classe précédé d'un tilde. Les constructeurs Les destructeurs Les fonctions amies L'appel d'une méthode se fait en précisant la méthode appelée et l'objet pour lequel on appelle cette méthode ( objet.méthode(...) ). Pratique: Les méthodes dont des fonctions normales dont un paramètre est donné par défaut: il s'agit de l'objet appelant la méthode. Les membres, données ou méthodes, de cet objet sont directement accessibles par leur nom ou par this ->données car this est un pointeur sur l'objet appelant. L'accès aux membres des autres objets se fait par objet.membre(). L'implémentation réelle des méthodes est souvent séparée de leur déclaration. Il faut alors utiliser un opérateur de résolution de portée noté :: pour indiquer à quelle classe se rapporte la méthode définie. Si l'implémentation de la méthode est faite dans la définition même de la classe, la méthode sera considérée inline, c'est à dire que le compilateur tentera de l'inclure directement dans les programmes au lieu de faire un appel de fonction normal. Remarques: La fonction new est une fonction C++ d'allocation dynamique de mémoire. Son utilisation est la suivante : pointeur_nouvel_objet = new type_objet. Son action est équivalente à celle de malloc avec en plus un appel au constructeur de l'objet créé. Il est donc possible de donner des arguments en écrivant : pointeur_nouvel_objet = new type_objet[nombre_objets]. La fonction delete permet de libérer la place mémoire allouée par new (équivalent au free pour malloc ). Son utilisation est la suivante: - pour un pointeur simple : delete pointeur, - pour un pointeur de tableau : delete[] pointeur_tableau , - l'utilisation de delete[] pour un pointeur simple ou delete pour un pointeur de tableau n'a pas de résultat défini. C'est donc une erreur. Exemple: typedef char booleen #define VRAI 1 #define FAUX 0 class liste { public: // constructeurs liste(); liste(liste&); // fonction permettant l'ajout d'un élément à la liste booleen ajoute(int); // destructeur ~liste(); protected: struct maillon { int valeur; maillon * suivant; }; maillon *debut_liste; }; // Méthode ajoute booleen liste::ajoute(int element) { maillon *nouveau; if ((nouveau = new maillon) == NULL) return FAUX; nouveau->valeur = element; nouveau->suivant = debut_liste; debut_liste = nouveau; retrun VRAI; } |
C++ : Les constructeurs
|
Théorie: Les constructeurs sont des méthodes particulières. Ils sont appelés à chaque fois qu'un objet est créé. Ils ont donc pour rôle d'initialiser des objets de façon correcte. En tant que fonction, ils peuvent avoir des arguments ce qui permet de créer des objets en leur donnant des valeurs si cela est nécessaire. Les constructeurs n'ont pas de type de retour. Pratique: En C++ deux types de constructeurs sont particulièrement importants. Ce sont: - les constructeurs sans argument qui permettent la construction de tableaux d'objets. - les constructeurs de recopie. Ces constructeurs prennent en argument un objet de la même classe que ceux qu'il créent et en font une copie. Cela est nécessaire pour les objets contenant des pointeurs. En effet, par exemple lors d'un appel de fonction, il y a recopie des arguments, comme en C, afin d'éviter qu'une modification sur un paramètre ne se répercute sur l'objet initial. Cependant, cette recopie de l'adresse contenue dans le pointeur et non de l'objet pointé. De ce fait si l'on modifie cet objet, il est donc impératif de créer un constructeur de recopie qui fasse une copie "en profondeur" des objets. Le constructeur par défaut sera déclaré comme suit: classe (const classe& objet). Le const indique que l'objet passé en argument ne peut pas être modifié. Cela renforce la sécurité dans le programme et permet la recopie d'objet déclaré constant. Le & indique que le paramètre est passé par adresse, c'est à dire que l'objet est passé directement sans recopie. Remarque: Il est nécessaire d'avoir un constructeur sans argument pour pouvoir construire des tableaux d'objets. Le masquage des données se faisant au niveau de la classe et non de l'objet, un objet peut avoir accès aux membres cachés d'un autre objet de même classe. L'appel aux membres d'un objet se fait comme pour une structure en C: par objet.membre ou pointeur_objet->membre. Exemple: Le constructeur sans argument liste::liste() { debut_liste = NULL; } Le constructeur de copie liste::liste(liste& source) { maillon *index, *nouveau; debut_liste = NULL; for(index=source.debut_liste;index!=NULL;index=index->suivant) { if ( (nouveau = new maillon) == NULL ) { cout << "Erreur : espace mémoire insuffisant " << endl; exit(1); } nouveau->valeur = index->valeur; nouveau->suivant = debut_liste; debut_liste = nouveau; } } |
C++ : Les destructeurs
|
Théorie: Les destructeurs sont des méthodes particulières. Ils sont appelés à chaque fois qu'un objet est détruit. Ils ont donc pour rôle principal de libérer la mémoire de façon correcte. En tant que fonction, ils ne prennent pas d'argument et n'ont pas de type de retour. Pratique: Les destructeurs sont essentiellement utiles lorsque des objets s'initialisent en s'allouant de la mémoire - usage de new, malloc ou toute autre fonction associée. Il est alors impératif de libérer cette mémoire lors de la destruction des objets. Exemple: liste::~liste() { maillon *index, *suivant_index; index = debut_liste; while(index!=NULL) { suivant_index = index->suivant; delete index; index = suivant_index; } } |
C++ - Les fonctions amies
|
Théorie: Les méthodes sont des fonctions dont le but est de permettre des opérations sur les données cachées des objets. Cependant les méthodes se distinguent particulièrement des fonctions par leur syntaxe d'appel. Cela peut créer des problèmes, notamment si l'on désire que l'objet appelant la méthode ne soit pas son premier argument. Heureusement;, il existe la possibilité en C++ de déclarer une fonction amie d'une classe. Cette déclaration donne à la fonction le droit de pouvoir accéder aux données cachées des objets de la classe. Il est donc possible de définir une fonction, appelée comme une fonction, qui a les mêmes caractéristiques qu'une méthode. De plus, une fonction peut être amie de plusieurs classes, lui donnant ainsi la possibilité d'accéder aux données privées de ces classes. Ceci est particulièrement avantageux pour des fonctions réalisant des opérations sur des objets de plusieurs classes. Pratique: La déclaration d'une fonction amie se fait à l'aide du mot clé friend suivi de la déclaration normale de la fonction. Les constructeurs et les destructeurs - ainsi que les fonctions virtuelles - ne peuvent être des fonctions amies : ce sont obligatoirement des méthodes. Exemple: Voir surcharge des opérateurs |
C++ - La surcharge des operateurs
|
Theorie: Le C++ permet de surcharger des fonctions, c'est à dire de déclarer plusieurs fonctions avec le même nom, tant qu'elles ont des types de paramè tres d'appel différents. Cela permet d'uniformiser l'utilisation des fonctions: il n'y a pas besoin de se souvenir du nom particulier d'une fonction pour un type particulier d'argument. Pratique: Le C++ offre une possibilité très intéressante qui est de pouvoir surcharger les opérateurs existants: +, -, *, /, <<, >>, etc, pour les objets d'une nouvelle classe. Il suffit pour cela de redéfinir les opé rateurs comme des méthodes ou fonctions amies normales. Pour les opérateurs autres que << et >> la redéfinition peut se faire de deux façons: 1. type_de_retour operator nom_opérateur (arguments); où operator est un mot clé du C++. Le premier argument de l'opérateur est implicite et correspond à l'objet appelant. Ainsi dans objet1 + objet2, objet1 est l'objet appelant le +. 2. friend type_de_retour nom_operatuer (argument1, arguments). Les opérateurs << et >> sont obligatoirement déclarés comme fonctions amies car ils prennent en premier argument le flot sur lequel ils agissent. Leur déclaration est donc de la forme: friend type_flot& operator << (type_flot&, type_objet). Les types de flots possibles sont principalement ostream pour une sortie et istream pour une entrée. ; Exemple: class liste { public: // opérateur de sortie sur flot friend ostream& oerator << (ostream&, liste); //opérateur d'assignation liste operator = (liste);... }; ostream& operator <<(ostream& flot, liste list){ liste::maillon *index; flot <<"( "; for(index=list.debut_liste;index!=NULL;index=index->suivant) flot<<index->valeur<<" "; flot <<")"; return flot; } liste liste::operator=(liste source){ // Si la liste est la même que la liste cible, on ne fait rien if (this == &source) return *this; // destruction des maillons de l'ancienne liste maillon *index, *suivant_index; index = debut_liste; while(index!=NULL) { suivant_index = index->suivant; delete index; index = suivant_index; } // copie de la liste source maillon *nouveau; debut_liste = NULL; for(index=source.debvut_liste;index!=NULL;index=index->suivant) { if ((nouveau = new maillon) == NULL){ cout <<" Espace mémoire insuffisant " << endl;exit(1); } nouveau->valeur = index->valeur; nouveau->suivant = debut_liste; debut_liste = nouveau; return *this; |
C++ - La classe Patron : Declaration des methodes
|
Theorie: Les méthodes des classes patron ont les mêmes propriétés que les méthodes normales. Seule leur syntaxe de définition change. Pratique: Pour des méthodes de classe patron, il est nécessaire, au moment de les définir, de rappeler qu'elles appartiennent à une classe patron. Cela se fait par la déclaration suivante: template<class T > type_retour nom_classe<T>: :nom_méthode(arguments) Il est alors possible d'utiliser T comme un spécificateur de type comme dans la classe. Exemple: template<class T> liste<T>::liste() { debut_liste = NULL; } template<class T> booleen liste<T>::ajoute(T element) { maillon *nouveau; if ((nouveau = new maillon) == NULL) return FAUX; nouveau->valeur = element; nouveau->suivant = debut_liste; debut_liste = nouveau; retrun VRAI; } template<class T> ostream& operator <<(ostream& flot, liste<T> list){ liste<T>::maillon *index; flot <<"( "; for(index=list.debut_liste;index!=NULL;index=index->suivant) flot<<index->valeur<<" "; flot <<")"; return flot; } template<class T> liste<T>::~liste(){ maillon *index, *suivant_index; index = debut_liste; while(index!=NULL) { Suivant_index = index->suivant; delete index; index = suivant_index; } } template<class T>liste<T> liste<T>::operator=(liste<T> source) { // Si la liste est la même que la liste cible, on ne fait rien if (this == &source) return *this; // Destruction des maillons de l'ancienne liste maillon *index, *suivant_index; index = debut_liste; while(index!=NULL) { suivant_index = index->suivant; delete index; index = suivant_index; } // Copie de la liste source maillon *nouveau; debut_liste = NULL; for(index=source.debvut_liste;index!=NULL;index=index->suivant) { if ((nouveau = new maillon) == NULL){ cout <<" Espace mémoire insuffisant " << endl; exit(1); } nouveau->valeur = index->valeur; nouveau->suivant = debut_liste;debut_liste = nouveau; } return *this; } |
C++ - La classe Patron : Specialisation des methodes
|
Theorie: Il est possible que, pour certains types de données particuliers, les méthodes patron générales ne soient pas applicables. Dans ce cas, il faut spécialiser les méthodes patron afin de prendre en compte ces cas particuliers. Cette spécialisation est équivalente à une surcharge de fonction. Pratique: La surcharge de la méthode patron se fait en indiquant explicitement le type du paramètre de type. Le C++ se chargera d'appeler la méthode redéfinie pour ce type particulier et la méthode patron générale pour les autres. Exemple: Si l'on désire pouvoir stocker dans la classe liste des chaînes de caractères, il est nécessaire de spécialiser certaines méthodes. liste<char*>::liste(liste<char*>&source){ maillon *index, *nouveau; debut_liste = NULL; ... } |
C++ - La derivation simple
|
Theorie: Supposons que l'on désire créer des listes telles qu'elles ne contiennent pas de répétition. Une solution serait de réécrire complètement une classe pour cela. Cependant, se faisant, nous ne profitons pas de la classe liste déjà existante et des fonctions qui restent valides: constructeurs, destructeurs, opérateurs, etc. Seule la méthode ajoute doit être modifiée. La solution consiste donc à considérer une liste sans répétition comme une liste et de redéfinir certaines fonctions. C'est ce que l'on appelle "dériver la classe liste". La nouvelle classe hérite des données et des méthodes de sa classe de base, ce qui définit un comportement par défaut. Une classe peut dériver de plusieurs classes de base. Par exemple, une classe ambulance pourrait dériver des classes voitures et véhicule_d_urgence. Pratique: Les classes de base d'une classe se déclarent ainsi: class nom_classe_dérivée : public nom_clase_base1, nom_clase_base2, ... { // Déclarations habituelles }; La classe dérivée a alors accès aux parties publiques des classes de base. Pour les parties cachées, il y a deux possibilités: 1. si la partie cachée a été déclarée private , la classe dérivée n'y a pas accès, 2. si la partie cachée a été déclarée protected , la classe dérivée y a accès. Dans le cas où la dérivation est publique, comme dans l'exemple précédent, les propriétés de protection (public, protected ou private) ne sont pas modifiées. Si la dérivation est protégée - utilisation du mot clé protected - les membres publiques ou protégés de la classe de base deviennent protégés dans la classe dérivée. Enfin, si la dérivation est privée - utilisation du mot clé private - les membres de la classe de base deviennent privés dans la classe dérivée. La dérivation publique est la plus utilisée. Il est alors possible de redéfinir des méthodes existantes dans les classes de base afin de modifier leur comportement, ou de créer de nouvelles méthodes spécialisées pour la nouvelle classe. Lors de la construction d'un objet d'une classe dérivée, il ya appel aux constructeurs des classes de base avant l'appel au constructeur de la classe dérivée. Des arguments peuvent être passés à ces constructeurs de la manière suivante: constructeur_derive(argument1, ..., argumentN) : constructeur_base1 (argumentX, argumentY, ...), constructeur_base2(...), ... . L'ordre des appels des constructeurs des classes n'est pas connu. Lors de la destruction des objets d'une classe dérivée, il y a appel aux destructeurs des classes de base dans l'ordre inverse de celui des constructeurs. Exemple: Déclaration d'une classe pour lister des entiers sans répétition class liste_sans_rep: public liste{ public: // Constructeurs liste_sans_rep(); liste_sans_rep(liste_sans_rep&); // Fonction ajoute redéfinie booleen ajoute(int); // Nouvelle fonction testant si un élément appartient à la liste booleen est_dans_liste(int); // Destructeur ~liste_sans_rep(); }; liste_sans_rep::liste_sans_rep(): liste() { } liste_sans_rep::liste_sans_rep(liste_sans_rep& list): liste(list) { } booleen liste_sans_rep::est_dans_liste(int element) { maillon *index; for(index=debut_liste;index!=NULL;index=index->suivant) if(index->valeur == element) return VRAI; return FAUX; } booleen liste_sans_rep::ajoute(int element) { if (est_dans_liste(element)) return FAUX; // Appel explicite à la fonction ajoute de la classe de base liste return liste: :ajoute(element); } liste_sans_rep::~liste_sans_rep() { } |
C++ - La derivation multiple
|
Theorie: Dans le cas où une classe hérite de propriétés provenant de différentes classes, il est nécessaire de réaliser un héritage multiple, c'est à dire de donner à la classe dérivée plusieurs classes de base. L'utilisation de l'héritage multiple peut poser certains problèmes comme celui de l'ambiguïté des noms si plusieurs classes de base ont des membres ayant le même nom. Nous ne traitons ici que des aspects généraux de l'héritage multiple, notamment dans le cas où une classe de base apparaît plusieurs fois dans le graphe d'héritage (sans envisager tous les cas possibles d'erreur). Dans le cas où une classe apparaît plusieurs fois dans le graphe d'héritage, il existe deux approches. Prenons un exemple: Nous avons une classe A de laquelle dérivent les classes B et C et enfin une classe D dérivant de B et C. Graphe d'héritageLa première approche consiste à créer cinq objets: un objet D, un objet B et un objet C, deux objets A - un pour l'objet B et un pour l'objet C. Héritage multiple avec répétition des objetsLa deuxième approche consiste à ne créer que quatre objets en identifiant les deux objets A précédents. Les objets B et C partagent donc alors le même objet de base. Cette approche est souvent plus proche de la conception naturelle de l'héritage. Héritage multiple dans répétition des objetsPratique: L'héritage multiple avec répétition des objets est identique à l'héritage simple avec simplement l'ajout de plusieurs noms de classe de base. L'héritage multiple sans répétition des objets est un peu plus complexe. Tout d'abord, les classes B et C partageant le même objet de base A, cela enfreint le paradigme de la protection des données. Il faut donc préciser dans les classes B et C que l'on autorise ce partage. Cela se fait en ajoutant le mot clé virtual à la définition de la dérivation: class B: virtual public A class C: virtual public A D'autre part comme il n'existe qu'un objet A, il est possible, dans le cas où l'on a un constructeur autre que celui par défaut, que les informations passées à ce constructeur par ceux de B et de C soient contradictoires. Il est donc nécessaire que ce soit le constructeur des objets de la classe D qui passe les informations pour la création de l'objet de base A. Le constructeur de la classe D est donc de la forme: D(...) : B(...), C(...), A(...) { .... }; |
C++ - Les fonctions virtuelles
|
Theorie: Le C++ permet à des pointeurs d'une classe de base de pointer sur des objets d'une classe dérivée. Par exemple, si A est une classe de base et B une classe dérivée de A, il est possible de déclarer: A *pointeur; B objet; pointeur = &objet; Cela est très pratique surtout pour stocker des objets. Il suffit en effet d'avoir un pointeur sur la classe de base car celui-ci peut pointer sur tout objet des classes dérivées. Cependant, comme le C++ possède un contrôle statique des types très contraignant, l'objet pointé ne pourra plus appeler que les méthodes de la classe de base. Cela limite l'utilité de ce stockage. Heureusement, le C++ offre une possibilité pour réduire ce problème: les fonctions virtuelles. En fait, il existe deux façons pour appeler les bonnes méthodes: 1. insérer dans les objets une information sur leur type et, à l'aide de tests manuels, appeler les méthodes des bonnes classes. Ces appels se font de la manière suivante: nom_classe::méthode(); 2. déclarer les méthodes virtuelles. Dans ce cas, il y aura à l'exécution la recherche du type effectif de l'objet pointé et appel de la bonne méthode. Pratique: La déclaration d'une méthode virtuelle se fait en ajoutant le mot clé virtual devant la déclaration de la méthode. Le programme cherchera alors à l'exécution, parmi les méthodes des classes dérivées ayant le même type de retour et des arguments de même type, celle qui appartient à la classe la plus proche de celle de l'objet appelant. Les constructeurs et les fonctions amies ne peuvent pas être déclarés virtuels. Exemple: Supposons que l'on désire stocker plusieurs listes, avec ou sans répétition, à l'aide d'un tableau de pointeurs sur liste avec répétitions. Afin d'empêcher l'ajout de doublons dans les listes sans répétition, nous allons rendre la méthode ajoute virtuelle. class liste { ... virtual booleen ajoute(int); ... }; main() { int index, index_liste; // Tableau de deux pointeurs de liste liste *liste_liste[2]; liste_liste[0] = new liste; liste_liste[1] = new liste_sans_rep; for(index_liste=0;index_liste<2;index_liste++){ for(index=0;index<10;index++) liste_liste[index_liste]->ajouter(index); for(index=0;index<10;index++) liste_liste[index_liste]->ajouter(index); } cout << "liste 1 : " << *(liste_liste[0]) << endl; cout << "liste 2 : " << *(liste_liste[1]) << endl; } nous donne: liste1 : ( 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 ) liste2 : ( 0 1 2 3 4 5 6 7 8 9 ) |
C++ - Les classes virtuelles
|
Theorie: Il est possible de déclarer des fonctions virtuelles pures. Cela signifie que: 1. la fonction est virtuelle 2. les classes dérivées de la classe dans laquelle cette déclaration a été faite doivent obligatoirement redéfinir cette fonction 3. la classe contenant la déclaration ne peut être instanciée, c'est à dire qu'il ne peut pas exister d'objet de ce type. Cette classe est appelée classe virtuelle. En fait, les classes virtuelles servent à donner les fonctionnalités minimales que les classes dérivées doivent fournir. De plus, comme il est possible de déclarer des pointeurs du type de la classe virtuelle, elles servent souvent de classe de stockage. Pratique: Pour déclarer une méthode virtuelle pure, il suffit d'ajouter après la déclaration de la méthode virtuelle = 0 . |
C++ - Les exceptions
|
Theorie: Le C++ offre un mécanisme de gestion des erreurs efficace. Habituellement, en cas d'erreur, le programme affiche un message et se termine plus ou moins proprement. Cela n'est malheureusement pas toujours satisfaisant surtout lorsque l'erreur est rattrapable. L'idée du mécanisme du C++ est, en cas d'erreur, de construire un objet contenant des informations sur l'erreur et de le lancer. Une fonction peut alors attraper l'objet et essayer de supprimer l'erreur. Si cette fonction n'y parvient pas, elle peut alors renvoyer l'objet, modifié ou non, ou mettre fin au programme. Par défaut, c'est à dire si aucune fonction ne peut supprimer l'erreur, cette dernière solution est adoptée, avec l'appel des fonctions unexpected, terminate , et enfin abort. Pratique: En C++, le lancement d'un objet se fait par: throw objet. L'objet peut alors être attrapé s'il existe un bloc try englobant l'endroit du programme où l'objet a été lancé, et s'il existe une fonction, déclarée avec catch après le bloc try , et prenant enfin comme argument un objet du type de l'objet lancé. Exemple: Schématiquement, la gestion des erreurs se fait ainsi: try { ... // Si erreur, lancement d'un objet throw objet; ... } catch(type_objet) { // Gestion de l'erreur ... } Il est possible d'avoir plusieurs catch avec des types d'objets différents afin de gérer plusieurs erreurs. Il est également possible de lancer une exception à l'intérieur d'un catch . Il y aura alors recherche d'un catch pouvant traiter l'objet. Si aucun catch n'a le bon type d'argument, le programme se termine. |
| Retour au choix des languages de programmation >> ici |