Exceptions, patrons de fonctions/classes et auto
Exceptions
Un morceau de code peu avoir un comportement variable selon le contexte.
Exemple
int 4 / b; // erreur si b == 0
FILE * f = fopen("emplacement", 'r');
Dans le cas ou le comportement n’est pas souhaité ou exceptionnel on dit qu’une exception est lancée/levée par le code. On peut “rattraper” l’exception avec une structure de contrôle de type try { /* ... */ } catch(/* ... */) { /* ... */ }
Exemple
using namespace std;
int division(int a, int b) {
if(b == 0)
throw 1; // exception lancée
else
return a / b;
}
int main(void) {
int val;
int ret;
cout << "Entrer un nombre" << endl;
cin >> val;
try {
ret = division(43/val);
} catch(int e) { // valeur throw = e
if(e == 1) { // excpetion attrapée
cout << "Impossible de diviser par zero" << endl;
return 1;
}
}
cout << "Le resultat de votre division est " << ret << endl;
return 0;
}
Si une exception n’est récupéré à travers une structure de controle try catch
elle est renvoyée à la fonction appelante si elle n’est capturée dans la fonction appelante elle est envoyée à la fonction appelante de la fonction appelante .
Si elle n’est n’est jamais capturée alors le programme s’interrompt brutalement (ducoup ce serait comme un exit(n)
.
On peut cumuler les blocs catch
. Si le code est suceptible de lever plusieurs exceptions. Le bloc qui est choisi est le premier qui “correspond” au type de l’exception lancée.
La correspondance est définie par :
- correspondance exacte de type
- si conversion implicite par héritage
Exemple
struct A { /*...*/ };
struct B: public A { /*...*/ };
try {
B b;
throw b; // ligne 6
} catch(long c) {
/* Pas exécuté car B != long */
} catch(A a) {
/* Récupére l'objet lancé en ligne 6 */
} catch(B b) {
/* Ne sera jamais exécuté */
}
Le bloc catch(...)
(c’est bien trois point) récupère toute exception non interceptée par les blocs catch précédents.
Exemple
try {
throw 1; // int est envoyé
} catch(long a) {
/* Jamais exécuté */
} catch(...) { // c'est bien trois points
/* Toujours exécuté */
}
On peut indiquer qu’une fonction ne renvoie pas d’exception en utilisant le mot clé noexcept
.
Exemple
int addition(int a, int b) noexcept {
return a + b;
}
Patron de fonctions de classe
Définition
Un patron de fonction (ou template) est une définition d’une fonction où un des paramètre est un type.
Exemple
// Exemple que l'on a fait en Algo et struct de données 2
template<class T>
T max(T a, T b) {
if(a > b)
return a;
else
return b;
}
// Exemple donnée pendant le cours de POO
template<typename T> max(T a, T b) {
if(a > b)
return a;
else
return b;
}
max<int> (3, 4);
max<float> (3.1, 6.7);
Lors d’un appel à un patron de fonction le compilateur génère le code de la fonction selon les arguments “types”. Pour cette raison les patron de fonction sont a définir dans les fichiers d’entête (fichier.h
) et ne sont pas présent dans les fichiers objet (fichier.o
)
On peut faire des patron de méthode/opérateur.
Lors d’un appel d’un patron de fonction les arguments “types” peuvent être omis dans ce cas le compilateur essaye de les trouver par unification.
Exemple
// types identique
max(3, 4); // ok ici équivalent à max<int>(3,4);
// Types différents
// max(3, 4l) // erreur ambiguité
max<long>(3, 4l); // Ok
On peut préciser plusieurs paramètres : template<typename A, typename B> A f(B a, int c);
Patron de classe
On peut créer des patrons de classe. Dans ce cas les arguments “types” doivent être explicites.
Exemple
struct B{ /*...*/ };
/* Définition */
template<typename T> struct maClVar {
/* ... */
T machin(int a);
};
/* Utilisation */
maClVar<int> a;
maClVar<maClVar<B>> d;
template<typename T> T maClVar<T>::machin(int a){ /*...*/}
Les paramètres de patron/fonction peuvent être des valeurs connues à la compilation.
Exemple
template<int a>
int f(int a) {
return a * b;
}
int main(void) {
int b;
std::cin >> b;
std::cout << f<3>(b); // ok
//std::cout << f<b>(3); // erreur
}
Le mot clé auto
On peut définir une variable avec auto
si le contexte permet d’établir le type de la variable à la compilation.
Exemple
auto a = 3; // variable a de type int
auto b = 3.; // variable b de tybe double
//auto c; // erreur