1 #ifndef __TABLEAU__
   2 #define __TABLEAU__
   3 
   4 #include <cstdlib>
   5 #include <iostream>
   6 using namespace std;
   7 
   8 // Un objet-fonction general, a un parametre
   9 template <typename T=float> class Functor1p {
  10 public:
  11     virtual T operator()(T) const = 0;
  12 };
  13 
  14 template <typename T=float> class Tableau {
  15 public:
  16 
  17         // Le constructeur principal - on passe la dimension du tableau en parametre
  18         explicit Tableau(size_t );
  19 
  20         // Le trio infernal
  21         Tableau (const Tableau & );
  22         Tableau & operator=(const Tableau &);
  23         ~Tableau();
  24 
  25         // renvoie la taille du Tableau
  26         size_t size() const { return sz;};
  27         
  28         // renvoie un element du Tableau sans deborder
  29         T & operator[](size_t i);
  30         
  31         // meme chose - version const
  32         T operator[](size_t i) const;
  33         
  34         // operateurs +=
  35         // Le parametre est un autre Tableau
  36         Tableau & operator+=(const Tableau & );
  37         
  38         // Le parametre est un T
  39         Tableau & operator+=(T );
  40         
  41         // imprime le Tableau sur la sortie standard
  42         void print () const;
  43         
  44         // La fonction transform: on leur passe un objet-fonction à 1 paramètre
  45         void transform(const Functor1p<T>& );
  46 
  47 private:
  48         const size_t sz;
  49         T *A;
  50         
  51         // Le signe __ rappelle qu'il s'agit de methodes privees
  52         void __copie (T src, T dest[], size_t s);
  53         void __copie (T src[], T dest[], size_t s);
  54 };
  55 
  56 // Une fonction qui n'est pas une methode
  57 template < typename T> Tableau<T> operator+(const Tableau<T>& t1, const Tableau<T>& t2);
  58 
  59 // Le constructeur principal - on passe la dimension du tableau en parametre
  60 template <typename T> Tableau<T>::Tableau(size_t n): sz(n) {
  61         cerr << "constructeur sz = " << n << '\n';
  62         A = (T *) malloc(sz*sizeof(T));
  63         __copie(0.0,A,sz);
  64 };
  65 
  66 // CE QUI SUIT ETAIT JUSQUE LA DANS LE .cpp
  67 
  68 // Le constructeur de copie - on fait l'alloc de memoire puis on copie
  69 template <typename T> Tableau<T>::Tableau (const Tableau<T> & t): sz(t.sz) {
  70         cerr << "constructeur de copie" << '\n';
  71         A = (T *) malloc(sz*sizeof(T));
  72         __copie(t.A,A,sz);
  73 };
  74 
  75 // L'operateur = PAS D'ALLOCATION DE MEMOIRE, c'est deja fait !!!
  76 template <typename T> Tableau<T> & Tableau<T>::operator=(const Tableau<T> &t) {
  77         cerr << "operateur =" << '\n';
  78         if (this==&t)    // Pour gerer les cas A=A
  79                 return *this;
  80         
  81         if (sz != t.sz) {
  82                 cerr << "Ne peut pas egaliser deux tableaux de tailles differentes" << '\n';
  83                 exit(1);
  84         };
  85         __copie(t.A,A,sz);
  86         return *this;
  87 };
  88 
  89 // Le destructeur: rendre la memoire au systeme
  90 template <typename T> Tableau<T>::~Tableau() { 
  91         cerr << "destructeur (sz = " << sz << ")\n";
  92         free(A);
  93 };
  94 
  95 // renvoie un element du tableau sans deborder
  96 // pas la peine de tester i < 0, size_t est un type unsigned
  97 // (decommentez ce qui suit vous verrez si cela compile)
  98 template <typename T> T & Tableau<T>::operator[](size_t i) {
  99         //if (i<0) {
 100         //  cerr << "ATTENTION Debordement de tableau - je renvoie tableau[0]\n";
 101         //  return *A;
 102         //} else
 103         if (i>=sz) {
 104                 cerr << "ATTENTION Debordement de Tableau - je renvoie Tableau[sz-1]\n";
 105                 return A[sz-1];
 106                 // return *(A+sz-1);  // Une autre manière d'écrire la même chose
 107         } else {
 108                 return A[i];
 109                 //return *(A+i);
 110         };
 111 };
 112 
 113 // meme chose - version const
 114 template <typename T> T Tableau<T>::operator[](size_t i) const {
 115         if (i>=sz) {
 116                 cerr << "ATTENTION Debordement de Tableau - je renvoie Tableau[sz-1]\n";
 117                 return A[sz-1];
 118         } else {
 119                 return A[i];
 120         };
 121 };
 122 
 123 // operateurs +=
 124 // Le parametre est un autre Tableau
 125 template <typename T> Tableau<T> & Tableau<T>::operator+=(const Tableau<T> & t) {
 126         if (sz != t.sz) {
 127                 cerr << "Ne peut pas ajouter deux Tableaux de tailles differentes" << '\n'; 
 128                 exit(1);
 129         } else {
 130                 for (size_t i=0; i < sz; i++) {
 131                         A[i] += t[i];
 132                 };
 133         };
 134         return *this;
 135 };
 136 
 137 // Le parametre est un T
 138 template <typename T> Tableau<T> & Tableau<T>::operator+=(T x) {
 139         for (size_t i=0; i < sz; i++) {
 140                 A[i] += x;
 141         };
 142         return *this;
 143 };
 144 
 145 // imprime le Tableau sur la sortie standard
 146 template <typename T> void Tableau<T>::print () const  {
 147         for (size_t i=0; i < sz; i++) {
 148                 cout << A[i] << " ";
 149         };
 150         cout << '\n';
 151 }
 152 
 153 // copie l'entier src dans la zone memoire pointee par dest
 154 template <typename T> void Tableau<T>::__copie (T src, T dest[], size_t s)
 155 {
 156         for ( size_t i=0; i<s; i++) {
 157                 dest[i] = src;
 158         }
 159 }
 160 template <typename T> void Tableau<T>::__copie (T src[], T dest[], size_t s) {
 161         for (size_t i=0; i<s; i++) {
 162                 dest[i] = src[i];
 163         };
 164 }
 165 
 166 // Deux autres manières d'écrire le même code: difficilement lisible, mais on voit ça souvent
 167 /*
 168 void Tableau::copie (float src, float *dest, size_t s) {
 169         for (size_t i=0; i<s; i++) {
 170                 *(dest++) = src;
 171         };
 172 };
 173 void Tableau::copie (float *src, float *dest, size_t s) {
 174         for (size_t i=0; i<s; i++) {
 175                 *(dest++) = *(src++);
 176         };
 177 }
 178 */
 179 
 180 // La famille de fonction transform: on lui passe un objet-fonction derive de Functor1p
 181 template <typename T> void Tableau<T>::transform(const Functor1p<T>& f ) {
 182         for (int i=0; i< sz; i++) 
 183                 A[i]=f(A[i]);
 184 };
 185 
 186 template <typename T> Tableau<T> operator+(const Tableau<T>& t1, const Tableau<T>& t2) {
 187         Tableau<T> s(t1.size());
 188         if (t1.size() != t2.size()) {
 189                 cerr << "Ne peut pas ajouter deux Tableaux de tailles differentes" << '\n'; 
 190                 exit(1);
 191         } else {
 192                 s = t1;
 193                 s += t2;
 194         };
 195         return s;
 196 };
 197 
 198 
 199 #endif