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