Télécharger la présentation
La présentation est en train de télécharger. S'il vous plaît, attendez
Publié parAlain Gabriel Modifié depuis plus de 10 années
1
9ième Classe (Mardi, 4 novembre) CSI2572
2
H Nous avons vu comment utiliser les directives #define #ifndef #endif Pour s’assurer de l’inclusion unique de certains fichiers. Il y a une autre utilitée potentielle à la directive #define. Écrire des macros: #define max(a, b) (((a) > (b)) ? (a) : (b)) La syntaxe utilise un nom, suivit de parenthèses dans lesquelles se trouvent des arguments. Les macros
3
#define PI 3.141592 #define ERRMSG "Une erreur s'est produite.\n" #define CARRE(x) (x)*(x) Le préprocesseur examine chaque ligne de code à la recherche du nom d’une macro ; s’il la trouve, il remplace le nom de la macro par sa valeur. Si la macro a un ou plusieurs paramètres, comme CARRE ci-dessus, ils sont remplacés littéralement par leur valeur effective. Ce processus se poursuit dans une ligne jusqu’à ce qu’il n’y ait plus de noms de macros, de sorte qu’une macro peut en contenir une autre, etc. (mais sans faire de cycle !).
4
if ( CARRE(d) > PI) printf(ERRMSG); sera transformée ainsi par le préprocesseur : if ( (d)*(d) > 3.141592) printf("Une erreur s'est produite.\n");
5
var1 = ( 80 + 10 ) * 20; var2 = 80 + 10 * 20; Attention: #define WIDTH 80 #define LENGTH1 ( WIDTH + 10 ) #define LENGTH2 WIDTH + 10 var1 = LENGTH1 * 20; var2 = LENGTH2 * 20;
6
#define CARRE(x) x * x //... j = CARRE(i+1); la dernière ligne deviendra : j = i+1 * i+1; qui est interprété comme i + (1*i) +1, soit 2*i+1. Attention:
7
#define CARRE(x) (x)*(x) //... int i = 3, j = CARRE(i++); en sortie i vaut 5, et non 4, parce que la macro a été étendue sous la forme (i++)*(i++) et provoque deux incrémentations. Ce genre d’erreur est particulièrement ardu à repérer. Attention:
8
#define getrandom(min, max) \ ((rand()%(int)(((max) + 1)-(min)))+ (min))
9
#define VAR(x) variable_##x les occurrences de VAR(1) par exemple seront remplacées par variable_1. On peut « coller » deux paramètres, ou un paramètre et un identificateur, à l’aide du symbole ##. Ainsi, si l’on écrit :
10
#define AFFICHE(x)\ printf("Valeur de #x = %d\n"\, (x) ) printf("Valeur de " "index" " = %d\n",(index) ) Les occurrences de AFFICHE(index) seront remplacées par : printf("Valeur de index = %d\n", (index) ) Enfin, en plaçant un # devant un paramètre, on demande son remplacement par la chaîne de caractères de son nom :
11
#define _Paste2(x, y) x##y #define noeud(typ) _Paste2(noeud_, typ) #define listedeclare(typ) \ class noeud(typ) { \ noeud(typ) *suivt; \ typ elm; \ public : \ noeud(typ)(typ e, noeud(typ) *suivant = 0) \ { elm = e; suivt = suivant; } \ noeud(typ) *suivant(void) { return suivt; } \ typ &contenu(void) { return elm; } \ }
12
#include "liste.h" #define declare(x, y) _Paste2(x, declare)(y) declare(liste, int); declare(liste, double); main(){ noeud(int) *ni = new noeud(int)(0); noeud(double) *nd = new noeud(double)(3.14); //... }
13
H Nous cherchons à écrire une fonction qui marche quel que soit le type des arguments (en autant que ca a un sens). Par exemple, calculer le maximum de 2 nombres à un sens pour tous les types numériques. Solutions: 1. Surcharger la fonction pour tous les types possibles (int, long, short, double, char, …). Il manque encore les classes de type numérique que l'on à définit soit même. Pas très pratique! 2. Écrire une macro: #define max(a, b) (((a) > (b)) ? (a) : (b)) Dangereux. Savoir ce qu'on fait. 3. Écrire un fonction template Les fonctions template:
14
template T max(const T& g, const T& d) { return ((g > d) ? g : d); } H max est une fonction, qui prend 2 arguments, tous les deux de type `T` et rend le maximum des deux, basé sur la définition de l'opérateur > comme il s'applique à T. La directive: template indique que la fonction est paramétrée par le type T. T devient ensuite un type normal dans la fonction.
15
int main(int, char **) { int i; int j; double a; double b; cout << max(i,j) << endl; cout << max(a,b) << endl; return 0; } cout << max(i,j) << endl; créée int max(const int&, const int&) cout << max(a,b) << endl; créée double max(const double&,const double&)
16
H Un template n’est pas un type, c’est un paramètre de construction d’un type. H Les templates sont utilisés pour construire E des fonctions E algorithmes génériques E des classes E types génériques avec implémentations communes Les fonctions template:
17
H Les classes génériques E Définit des familles de classes E Souvent utilisées pour les conteneurs "fonctions templates" et classes template class pair { public: T1 first; T2 second; pair (const T1& a, const T2& b): first (a), second (b) {} };
18
H Utilisation des classes génériques On doit désigner explicitement les types pour lesquels on utilise le template Exemple : une paire de strings et de doubles "fonctions templates" et classes int main () { pair e («E1», 23.45); cout << e.first << « » << e.second << endl; }
19
H Pour combiner pair et max il faut définir l’opérateur < pour des paires : "fonctions templates" et classes template bool operator < const pair & a, const pair & b) { return (a.second < b.second); }
20
H Classe Array Cas concret:
21
template class Array { private: int len_; T* data_; int check(int i) const { if (i = len_) throw BoundsViol("Array", i, len_); return i; }
22
public: Array(int len=10): len_(len), data_(new T[len]) { } ~Array(){ delete [] data_; } int len() const { return len_;} const T& operator[](int i) const { return data_[check(i)]; } T& operator[](int i) { return data_[check(i)]; } Array(const Array &); Array & operator= (const Array &); };
23
int main() { Array ai; Array af; Array ac; Array as; Array > aai; } H les instantiations de classes template doivent être explicitement paramêtrées: H Notez l'espace entre les deux >'s dans le dernier exemple. Sans cet espace, le compilateur verrait un >> (symbol de décalage binaire) au lieu de deux >'s.
Présentations similaires
© 2024 SlidePlayer.fr Inc.
All rights reserved.