int Min(int a, int b) { |
return (a<b)?a:b ; |
} |
-->
autant de fonctions à écrire que de types à gérer
!!!const int Dim=100; |
class TabInt { |
int tab[Dim]; |
public: |
int& operator[](int); |
void sort(); ... |
}; |
-->
Généricité : possibilité de paramétrer les
définitions de fonction ou de classeFonction générique (1) |
template <class T> // template = gabarit |
T Min(T a,T b) { |
return (a<b)?a:b ; |
} |
int main() { |
int i=1, j=3, k; float x=1.4, y=2.5, z; |
myClass a, b, c; |
... |
k = Min(i,j); |
z = Min(x,y); |
c = Min(a,b); // OK |
// (si operator<(myClass,myClass) défini) |
} |
Fonction générique (2) |
-->
se
reporter à une documentation digne de ce nom !!!.
char* Min (char *s1, char *s2) { |
return( (strcmp(s1,s2)<0) ? s1 : s2); |
} |
Classe générique (1) |
template <class type> |
class Tableau { |
type tab[Dim]; |
public : |
type& operator[](int); |
void sort(void); |
... |
}; // --> Tableau<type> nouveau type.
|
template <class type> |
void Tableau<type>::sort(void) { ... } |
Tableau<int> soldes ; |
Tableau<compte> comptes ; |
Classe générique (2) |
// Spécialisation de méthode |
Tableau<char*>::method(args) { ...} |
// Spécialisation de classe |
class Tableau<String> { |
// redéfinition complète... }; |
// définition |
template <class type, int size> |
class Tableau { |
type tab[size]; |
... }; |
// utilisation |
const int defSize=10; |
Tableau<float, 10*defSize> tab ; |
Syntaxe de la généricité |
Héritage et généricité |
template <class T> |
class Pile : private Liste<T> { ... }; |
-->
la classe dérivée hérite de la propriété de
généricité.
Relations d'amitiés génériques (1) |
template <class T> class A { |
friend class AutreClasse; |
// ... |
}; |
template <class T> class A { |
friend class B<T>; |
// ... |
}; |
Relations d'amitiés génériques (2) |
template <class Type> class A { |
template <class T> |
friend class B; |
template <class T> |
friend void C<T>::meth(); |
// ... |
}; |
Exemple : Tableau générique |
#ifndef _tableau_h |
#define _tableau_h |
template < class T> class tableau { |
public: |
// construteurs |
tableau(unsigned int nbElts); |
tableau(unsigned int nbElts, T valInit); |
tableau(const tableau<T>&); |
//destructeur |
~tableau(); |
// operateurs |
virtual T& operator[] (unsigned int ind) const; |
// fonctions |
unsigned int longueur(void) const; |
unsigned int setnbElts(unsigned int nbElts); |
// Modif. _nbElts + valeur initiale |
unsigned int setnbElts(unsigned int nbElts, |
T& valInit); |
protected: |
T * data; |
unsigned int _nbElts; |
}; |
#endif |
#include <assert.h> |
#include "tableau.h" |
template<class T> |
tableau<T>::tableau(unsigned int nbElts) |
: _nbElts(nbElts) |
{ data = new T[_nbElts]; |
assert(data!=0); } |
template<class T> |
tableau<T>::tableau(unsigned int nbElts, |
T valinit) : _nbElts(nbElts) |
{ data = new T[_nbElts]; |
assert(data!=0); |
for (int i=0; i<_nbElts; i++) |
data[i]=valinit; } |
template<class T> |
tableau<T>::tableau(const tableau<T> & source) |
: _nbElts(source._nbElts) |
{ data = new T[_nbElts]; |
assert(data!=0); |
for (int i=0; i<_nbElts; i++) |
data[i]=source.data[i]; } |
template <class T> tableau<T>::~tableau() |
{ delete [] data; |
data = 0; |
_nbElts = 0; } |
template<class T> |
T & tableau<T>::operator[] (unsigned int ind) const |
{ assert((ind<_nbElts) && (0<=ind)); |
return(data[ind]); } |
template<class T> |
unsigned int |
tableau<T>::setnbElts(unsigned int nbElts) |
{ T * newData = new T[nbElts]; |
assert(newData!=0); |
int fin = min(nbElts,_nbElts); |
for(int i=0;i<fin;i++) |
newData[i]=data[i]; |
delete [] data; |
_nbElts = nbElts; data = newData; |
return _nbElts; } |
template<class T> |
unsigned int |
tableau<T>::setnbElts(unsigned int nbElts, |
T & valinit) |
{ T * newData = new T[nbElts]; |
assert(newData!=0); |
int fin = min(nbElts,_nbElts); |
for(int i=0;i<fin;i++) |
newData[i]=data[i]; |
_nbElts = nbElts; |
for(int i=fin;i<_nbElts;i++) |
newData[i]=valinit; |
delete [] data; |
data = newData; |
return _nbElts; } |
template<class T> |
unsigned int tableau<T>::longueur(void) const |
{ return _nbElts; } |
Exemple : File générique |
#ifndef file_h |
#define file_h |
#include <iostream.h> |
// Déclaration avant définition |
template <class Type> class File; |
// Element d'une file |
template <class Type> |
class EltFile { |
public: |
friend class File<Type>; |
EltFile( const Type &t ) : elemt( t ) |
{ next = 0; } |
private: |
Type elemt; |
EltFile *next; |
}; |
template <class Type> |
ostream& |
operator<<(ostream&,EltFile<Type>&); |
File (suite) |
template <class Type> |
class File { |
public: |
File() { tete = queue = 0; } |
~File(); |
void enleve(); |
Type valeur(); |
void ajoute( const Type& ); |
int vide() { return tete==0 ? TRUE : FALSE; } |
private: |
EltFile<Type> *tete; |
EltFile<Type> *queue; |
}; |
template <class Type> |
ostream& |
operator<<(ostream&,File<Type>&); |
#endif |
Correction et validité |
-->
tests dynamiques lors de l'exécution-->
utilisation :
Assertions et programmation par objets |
Expression des assertions |
void assert(á expression ñ) ; |
(Pré-/Post-)condition |
void pile::depiler(void) { |
// pré-condition |
assert(!vide()); |
// ... |
} |
void pile::empiler(int element) { |
// ... |
// post-condition |
assert(sommet() == element); |
} |
Invariant |
template <class type> class pile { |
protected: |
int taille, i; type *rep; |
int invariant(void) const; |
public: |
void empiler(type element); |
... }; |
template <class type> |
int pile<type>::invariant(void) const { |
return( (rep!=0) && (taille>=0) |
&& (i<=taille) && (i>=0) ); } |
template <class type> |
void pile<type>::empiler(type element) { |
... |
rep[i++] = element; |
assert(invariant()); |
} |
Suspension de vérification |
-->
compilation avec -DNDEBUG, les assertions
sont ignorées.
Exception |
Exemple (1) |
// Sans les exceptions : |
action1 ; |
if erreur1 { ...} |
else { |
action2 ; |
if erreur2 { ...} |
else { |
action3 ; |
if erreur3 { ...} |
else { ... |
Expression des exceptions |
int * pt = new int[taille]; |
if (pt==0) |
throw "Echec allocation"; |
enum IndErrs { IndxTooSmall, IndxTooBig }; |
if (i<0) |
throw IndxTooSmall; |
class outRangeVal { ... |
public: |
outRangeVal(const char *, int); |
reparer(); |
... }; |
// ... |
if (tab[i]>Tmax) |
throw outRangeVal("Too big value",i); } |
Gestion des exceptions |
try { // Expression du code |
// générateur potentiel d'exceptions |
alloue(); |
initialise(); |
process(); |
} |
// traitement des exceptions |
catch(char * str){ |
cerr << str << "\n"; |
exit(-1); |
} |
catch(outRangeVal& exc){ |
exc.reparer(); |
} |
Propagation des exceptions |
Exemple (2) |
// Solution avec les exceptions : |
class exc1; |
class exc2; |
class exc3; |
try { |
// module de détection |
action1 ; |
if erreur1 throw exc1( ...) ; |
action2 ; |
if erreur2 throw exc2( ...) ; |
action3 ; |
if erreur3 throw exc3( ...) ; |
} |
// module de traitement |
catch (exc1& e) { ...} ; |
catch (exc2& e) { ...} ; |
catch (exc3& e) { ...} ; |
Exemple : Pile |
#ifndef _pile_h |
#define _pile_h |
template <class type> |
class pile { |
protected: |
int taille; |
int i; |
type *rep; |
int invariant() const; |
public: |
pile(int i=10); |
~pile(); |
void empiler(type element); |
void depiler(); |
const type& sommet() const; |
int vide() const; |
int pleine() const; |
}; |
#endif |
#include <assert.h> |
#include "pile.h" |
template <class type> |
pile<type>::pile(int t):i(0),taille(t) { |
rep = new type[taille]; |
assert(invariant()); } |
template <class type> |
pile<type>::~pile(void) { |
delete [] rep; } |
template <class type> |
int pile<type>::vide(void) const { |
return i==0; } |
template <class type> |
int pile<type>::pleine(void) const { |
return i==taille; } |
template<class type> |
void pile<type>::depiler(void) { |
if (vide()) |
throw "impossible: pile vide"; |
i--; |
assert(invariant()); } |
template <class type> |
void pile<type>::empiler(type element) { |
if (pleine()) |
throw "impossible: pile pleine"; |
rep[i++] = element; |
assert(invariant()); |
// post-condition |
assert(sommet() ==element); } |
template <class type> |
const type& pile<type>::sommet(void) const { |
if (vide()) |
throw "impossible: pile vide"; |
return rep[i-1]; } |
template <class type> |
int pile<type>::invariant(void) const { |
int v = (rep != 0); |
v &&= (taille >= 0); |
v &&= (i <= taille); |
v &&= (i>=0); |
return v; } |
#include <iostream.h> |
#include <stdlib.h> |
#include "pile.h" |
const line = 80; |
int main(void) |
{ |
pile<int> p1; |
char rep[line]; |
do |
{ |
cout << "Entrer une commande (edsq) : "; |
cin >> rep[0]; |
try |
{ |
switch(rep[0]) { |
case 'e' : |
cout << "Entrer une valeur : "; |
cin >> rep; |
p1.empiler(atoi(rep)); |
break; |
case 'd' : |
p1.depiler(); |
break; |
case 's' : |
cout << "sommet : " ; |
cout << p1.sommet() << "\n"; |
break; |
case 'q' : |
break; |
default : |
throw "Attention a la syntaxe"; |
break; |
} |
} |
catch (const char* msg) |
{ |
cerr << msg << endl; |
cerr << "Commande ignoree\n"; |
} |
} while (rep[0] != 'q'); |
return 0; |
} |
/usr/include
/lib/libc.a
Fichiers d'en-tête standards |
<string.h> |
<stdlib.h> |
<ctype.h> |
<math.h> |
n
: integer);ceil
et floor
);<time.h> |
sleep(
durée-en-secondes);