Recouvrement des fonctions

En pratique, il existe de nombreuses fonctions dont l’effet est plus général que leur implantation courante. Par exemple, la fonction de maximum :

inline int max (int a, int b){    if (a > b) return a; else return b; }

est en réalité plus générale que cela, car on peut aussi souhaiter avoir le maximum de variables de type long, par exemple, ou double. Dans de nombreux langages de programmation, et en C, il faudrait écrire des versions spéciales de cette fonction, avec des noms différents, tels que maxlong, maxdouble, etc. En C++, il est possible de donner le même nom à toutes ces fonctions :

inline int max (int a, int b){    if (a > b) return a; else return b; }				inline long max (long a, long b){    if (a > b) return a; else return b; }				inline double max (double a, double b){    if (a > b) return a; else return b; }

On dit que l’on a réalisé un recouvrement de fonctions. Lorsque le compilateur rencontre des appels à max, il sélectionne la bonne fonction selon le type des arguments :

int i = 1, j = 3;i = max(i, j);            // appel de max(int, int)double d1, d2;d1 = max(d1, d2);         // max(double, double)

Dans certains cas, cependant, on peut se demander ce qui va se passer :

float f1, f2;f1 = max(f1, f2);            // quelle fonction ?

Ici, le compilateur applique les règles standard de promotion des types ; le type float peut être changé en double sans perte de précision, c’est donc max(double, double) qui est appelée, et le résultat est donc correct. Cependant, si nous n’avions pas écrit cette fonction, le compilateur aurait protesté dans l’appel précédent, en indiquant Error : Ambiguity between 'max(long, long)' and 'max(int , int)', ambiguïté entre max(long, long) et max(int, int), car il n’est pas possible de faire passer une variable float par l’un des types long ou int sans perte de précision.

Cette règle de promotion des types nous évite d’écrire des fonctions pour chaque type, ce qui serait fastidieux. On aurait même pu éviter d’écrire une fonction max(int, int). Dans ce cas, tous les types entiers (char, unsigned char, unsigned, int, unsigned long, long) utiliseraient la version max(long, long), tandis que float et double utiliseraient max(double, double). Seul le type long double ne pourrait être utilisé, sauf en précisant explicitement une transformation de type :

long double ld1, ld2;ld1 = max( (double) ld1, ld2);

Dans ce cas, le premier argument permet au compilateur de résoudre l’ambiguïté (il n’est pas nécessaire de préciser un second changement de type) ; cependant, il y a une perte de précision, il est donc préférable d’écrire une nouvelle version de max.

Signalons que le cas des fonctions ayant des références pour paramètres est différent. Supposons écrites par exemple les fonctions :

inline void echange(int& a, int&  b){    int c = a; a = b; b = c; }				inline void echange(long& a, long& b){    long c = a; a = b; b = c; }				inline void echange(double& a, double& b){    double c = a; a = b; b = c; }

Dans ce cas, si l’on écrit :

float f1, f2;echange(f1, f2);            // pas de concordance

le compilateur signale à nouveau une ambiguïté car la promotion des types ne s’applique pas aux références. On peut essayer d’écrire :

echange( (double) f1, f2);

mais alors le compilateur prévient qu’il utilisera une variable temporaire pour f2 (Warning : Temporary used for parameter 'b' in call to 'echange(double, double)', variable temporaire utilisée pour le paramètre 'b' dans l’appel de 'echange(double, double)'). Si vous essayez quand même, une variable temporaire est en fait utilisée pour les deux paramètres, et l’appel est sans effet. En fait, une variable float ne peut être considérée comme identique à une double, même dans une opération aussi simple. La meilleure solution consiste donc à écrire une version de echange pour chaque type.

D’une façon générale, deux fonctions sont considérées comme différentes si elles ont une liste d’arguments différente, et dans ce cas elles peuvent avoir le même nom. Par contre, si seul le type de résultat renvoyé est différent, le compilateur ne peut pas distinguer les deux fonctions et affichera un message d’erreur si on les utilise.

Précédent Précédent Sommaire Sommaire Suivant Suivant