23
9ième Classe (Mardi, 4 novembre) 9ième Classe (Mardi, 4 novembre) CSI2572 CSI2572

9ième Classe (Mardi, 4 novembre) CSI2572

  • Upload
    chava

  • View
    36

  • Download
    0

Embed Size (px)

DESCRIPTION

9ième Classe (Mardi, 4 novembre) CSI2572. Les macros. 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. - PowerPoint PPT Presentation

Citation preview

Page 1: 9ième Classe (Mardi, 4 novembre) CSI2572

9ième Classe (Mardi, 4 novembre)9ième Classe (Mardi, 4 novembre)CSI2572CSI2572

Page 2: 9ième Classe (Mardi, 4 novembre) CSI2572

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 lesquellesse trouvent des arguments.

Les macros

Page 3: 9ième Classe (Mardi, 4 novembre) CSI2572

#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 !).

Page 4: 9ième Classe (Mardi, 4 novembre) CSI2572

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");

Page 5: 9ième Classe (Mardi, 4 novembre) CSI2572

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;

Page 6: 9ième Classe (Mardi, 4 novembre) CSI2572

#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:

Page 7: 9ième Classe (Mardi, 4 novembre) CSI2572

#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:

Page 8: 9ième Classe (Mardi, 4 novembre) CSI2572

#define getrandom(min, max) \ ((rand()%(int)(((max) + 1)-(min)))+ (min))

Page 9: 9ième Classe (Mardi, 4 novembre) CSI2572

#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 :

Page 10: 9ième Classe (Mardi, 4 novembre) CSI2572

#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 :

Page 11: 9ième Classe (Mardi, 4 novembre) CSI2572

#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; } \}

Page 12: 9ième Classe (Mardi, 4 novembre) CSI2572

#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); // ...}

Page 13: 9ième Classe (Mardi, 4 novembre) CSI2572

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:

Page 14: 9ième Classe (Mardi, 4 novembre) CSI2572

template <class T> T max(const T& g, const T& d) {

return ((g > d) ? g : d);

}

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 <class T> indique que la fonction est paramétrée par le type T. T devient ensuite un type normal dans la fonction.

Page 15: 9ième Classe (Mardi, 4 novembre) CSI2572

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ééedouble max(const double&,const double&)

Page 16: 9ième Classe (Mardi, 4 novembre) CSI2572

Un template n’est pas un type, c’est un paramètre de construction d’un type.

Les templates sont utilisés pour construire des fonctions algorithmes génériques des classes types génériques avec implémentations communes

Les fonctions template:

Page 17: 9ième Classe (Mardi, 4 novembre) CSI2572

Les classes génériques Définit des familles de classes Souvent utilisées pour les conteneurs

"fonctions templates" et classes

template <class T1, class T2> class pair {

public:

T1 first; T2 second; pair (const T1& a, const T2& b): first (a), second (b) {}

};

Page 18: 9ième Classe (Mardi, 4 novembre) CSI2572

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 <string, double> e («E1», 23.45); cout << e.first << « » << e.second << endl;

}

Page 19: 9ième Classe (Mardi, 4 novembre) CSI2572

Pour combiner pair et max il faut définir l’opérateur < pour des paires :

"fonctions templates" et classes

template <class T1, class T2> bool operator < const pair<T1, T2>& a, const pair<T1, t2>& b) {

return (a.second < b.second); }

Page 20: 9ième Classe (Mardi, 4 novembre) CSI2572

Classe Array

Cas concret:

Page 21: 9ième Classe (Mardi, 4 novembre) CSI2572

template<class T>

    class Array {

       private:

     int len_;      T*  data_;

      int check(int i) const {

if (i < 0 || i >= len_) throw BoundsViol("Array", i,

len_);         return i;

}

Page 22: 9ième Classe (Mardi, 4 novembre) CSI2572

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<T>&);

Array<T>& operator= (const Array<T>&);

};

Page 23: 9ième Classe (Mardi, 4 novembre) CSI2572

    int main()

    {

      Array<int>           ai;

      Array<float>         af;

      Array<char*>         ac;

      Array<String>        as;

      Array< Array<int> >  aai;

    }

les instantiations de classes template doivent être explicitement paramêtrées:

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.