Académique Documents
Professionnel Documents
Culture Documents
LA GENERICITE
Plan du chapitre :
I. Définition …………………………………………………………………………………………………
………………………………………………………………………………………………………. 87
II. Fonctions génériques ….………………………………………………………………………………
…………………………………. 87
III. Classes génériques ………………………………………………...……………………
……………………… …………………………………... 91
Objectifs du chapitre :
Comprendre la notion de généricité en C++.
Connaître
tre et manipuler des fonctions et classes génériques avec le langage C++.
C++
I. Définition:
Parmi les techniques présentées pour améliorer la réutilisabilité, nous avons présenté la notion de
généricité, qui permet de paramétrer les fonctions et les classes par un type de données.
La généricité permet d'avoir des fonctions et des classes paramétrables, c'est-à-dire que, au
moment où nous en avons besoin, nous précisons le type à utiliser pour ladite fonction ou ladite
classe. C'est le type qui est paramétrable. Ce concept nous permettra d'avoir des écritures plus
concises et ainsi d'éviter de nombreuses surdéfinitions.
La généricité est souvent appelée « template » ( patron – évocation de la haute couture), ou
également « modèle ».
Lors d’un appel à la fonction min, le type des paramètres est alors considéré et l’implantation
correspondante est finalement appelée. Ceci présente cependant quelques inconvénients :
La définition des 2 fonctions mène à des instructions identiques, qui ne sont différenciées que
par le type des variables qu’elles manipulent. On s’aperçoit ici que plus qu’une fonction, on
souhaiterait exprimer une méthode, valable pour n’importe quel type manipulé : la fonction min
est la fonction qui renvoie le plus petit des paramètres qui lui est fourni. Cet élément est
déterminé grâce à l’opérateur < qui établit une relation d’ordre sur le type d’élément considéré.
Si on souhaite étendre la définition de cette fonction à de nouveaux types, il faut définir une
nouvelle implantation de la fonction min par type considéré.
Une autre solution est de définir une fonction template, c’est-à-dire générique. Cette définition
définit en fait un patron de fonction, qui est instancié par un type de données (ici le type T) pour
produire une fonction par type manipulé.
Il n’est donc plus nécessaire de définir une implantation par type de données. De plus, la fonction
min est valide avec tous les types de données dotés de l’opérateur <. On définit donc bien plus
qu’une fonction, on définit une méthode permettant d’obtenir une certaine abstraction en
s’affranchissant des problèmes de type.
Remarques :
Il est possible de définir des fonctions template acceptant plusieurs types de données en
paramètre. Chaque paramètre désignant une classe est alors précédé du mot-clé class, comme
dans l’exemple: template <class T, class U> ....
Chaque type de données paramètre d’une fonction template doit être utilisé dans la définition
de cette fonction.
Pour que cette fonctionnalité soit disponible, les fonctions génériques doivent être définies dans
des fichiers d’interface (fichiers .H). Les fonctions template sont en effet expansées elles aussi.
Ainsi, chaque appel fait à ce genre de fonctions est remplacé, à la pré-compilation, par le code
source correspondant à la fonction.
int n ; char c ;
Que va faire le compilateur en présence d’un appel tel que min (n,c) ou min (c,n) ? En fait, la règle
prévue par C++ dans ce cas est qu’il doit y avoir correspondance absolue des types. Cela signifie
que nous ne pouvons utiliser le patron min que pour des appels dans lesquels les deux arguments
ont le même type. Manifestement, ce n’est pas le cas dans nos deux appels, qui aboutiront à une
erreur de compilation.
On notera que, dans cette correspondance absolue, l’éventuel qualificateur const intervient.
Voici quelques exemples d’appels de min qui précisent quelle sera la fonction instanciée lorsque
l’appel est correct:
int n ; char c ; unsigned int q ;
const int ci1=10, ci2=12 ;
int t[10] ;
int *adr=n ;
min(n,c) ;//erreur
min(n,q) ; //erreur
min(n, ci1) ; //erreur :const int et # de int
min(ci1, ci2) ;// min(cons tint, cons tint)
min(t,adr) ;//min (int *, int *)
Il est cependant possible d’intervenir sur un mécanisme d’identification de type. En effet, C++
vous autorise à spécifier un ou plusieurs paramètres de type au moment de l’appel du patron.
Voici quelques exemples utilisant les déclarations précédentes :
min<int>(c,n)
force l’utilisation de min<int>, et donc la conversion de c en int ; le résultat sera de type int
min<char>(q,n)
force l’utilisation de min<char>, et donc la conversion de q et n en char ; le résultat sera de
type char
Autre exemple :
template <class T, class U> T fct(T x,U y,T z)
{
return x+y+z ;
}
...
int n,p ; float x ;
cout << fct<int ,float>(n, p, x); n et x: int et p: float
A côté du patron de classe, il faut écrire une spécialisation de la fonction min pour le type
char *.
template <class T>
T min (T x, T y)
{
return ((x<y) ? x:y);
}
char * min (char * c1, char * c2)
{
return ((strcmp(c1,c2)<0)?c1:c2);
}
De même il est possible de surdéfinir une fonction classique, il est possible de surdéfinir un patron
de fonctions, c’est-à-dire de définir plusieurs patrons possédant des arguments différents. On
notera que cette situation conduit en fait à définir plusieurs « familles » de fonctions.
Exemple:
//Patron numero I
template <class T> T min (T x, T y)
{
return ((x<y) ? x:y);
}
//Patron numero II
template <class T> T min (T x, T y, T z)
{
return min(min(x,y),z);
}
vect(int,int) ;
void afficher() ;
int operator <(vect v)
{
return x*x+y*y <v.x*v.x+v.y*v.y ;
}
};
void main()
{
vect v1(3,2),v2(4,1), v ;
v=min(v1, v2) ;
v.afficher() ;// affichage de v1(3,2)
}
void main()
{
Tableau <complexe> A;
A[0]=complexe(1,2);
}
Remarques :
Comme dans le cas des fonctions template, tout le code source correspondant à des classes
template (y compris la définition de leurs méthodes) doit se trouver dans l’interface de la
classe correspondante.
Une classe template permet de définir des attributs, des paramètres ou des valeurs de retour de
méthodes template. De façon réciproque, pour pouvoir définir des entités template à
l’intérieur d’une classe, la classe doit elle-même être template.
Attention à la syntaxe des méthodes template définies en dehors du corps de la classe. La
définition se fait :
template <class T> typeRetour nomClasse<T>::nomMéthode(params).