Arguments par défaut

Il est très fréquent que certains paramètres d’une fonction prennent une valeur particulière plus souvent que d’autres, ou encore ne servent à rien dans certains cas.

Imaginons par exemple une procédure qui ajoute une chaîne à la fin d’une autre. Un tel ajout peut provoquer un débordement, aussi n’est-il pas inutile de donner un paramètre indiquant la taille maximale à ne pas dépasser pour la chaîne résultat. Voici une implantation possible d’une telle fonction :

char* ajoute(char *dest, const char *ajout,  int max)
// ajoute la seconde chaîne à la première, sans
// dépasser la taille max pour le résultat.
{
     int ld = strlen(dest), la = strlen(ajout);
     if ( (max > ld +la) || (max <= 0) ) max =0;
     else la = max -ld -1;
     if (la > 0) memmove(dest+ld, ajout, la);
     if (max) *(dest+max) = 0;    // zéro final
     return dest;
}

On ignore ici le paramètre max s’il est négatif ou nul, la seconde chaîne est alors recopiée entièrement derrière la première. Si ce paramètre est inférieur à la longueur de dest la chaîne est simplement tronquée, ajout ne sert à rien. Voici un exemple d’utilisation de cette fonction :

char s1[10] = "Hello! ", s2 = "Comment allez-vous ?";
ajoute(s1, s2, 10);

La chaîne s1 vaut alors "Hello! Com", soit 10 caractères, en comptant le zéro final, et remplit donc entièrement la mémoire qui lui est attribuée.

Cependant, dans de nombreux cas, on n’a pas besoin de préciser un paramètre max, parce qu’on est sûr qu’il n’y aura pas débordement. On précise alors une valeur nulle pour max, qui signifie conventionnellement « toute la place disponible » . Par exemple, dans ce cas :

char tampon[256] = "";
ajoute(tampon, s, 0);
ajoute(tampon, s2, 0);

De tels cas sont très fréquents en pratique. Mais on en voit clairement l’inconvénient : il faut préciser un troisième argument inutile, dont la valeur conventionnelle doit être retenue par coeur (cela peut être plus complexe que 0).

En C++, on peut donner une valeur par défaut à un argument de fonction, comme ceci :

char *ajoute(char *dest, const char *ajout,
              int max = 0 )
// reste identique...

Dans ce cas, on peut appeler la fonction sans préciser ce paramètre, qui prend alors la valeur par défaut indiquée :

char tampon[256] = "";
ajoute(tampon, s);
ajoute(tampon, s2);

est ici équivalent à l’écriture précédente, mais plus sobre.

Ces arguments par défaut sont une capacité très intéressante de C++, qui permet des écritures beaucoup plus agréables. On peut ainsi regrouper plusieurs fonctions. Par exemple, il existe deux fonctions de copie dans la librairie <string.h> (qui est écrite en langage C, non en C++) :

char *strcpy(char *dest, const char *source);

qui recopie entièrement source dans dest, que nous connaissons déjà, et :

char *strncpy(char *dest, const char *source,  size_t max)

qui copie au plus max caractères de source vers dest. On voit qu’avec les arguments par défaut, une seule fonction aurait suffi, comme ceci par exemple :

char *strcpy(char *dest, const char *source,
size_t max = 65535);

Une fonction peut avoir plusieurs arguments par défaut, qui peuvent être des expressions constantes de toutes sortes :

void f(int a, double d = 2*Pi, int n =  0);
int g(long n = -1, void *p = NULL);

Cependant seuls les derniers arguments peuvent avoir une valeur par défaut, il n’est pas possible de faire un mélange :

int h(long n =0, int i, float f =1); // non, mélange!

D’autre part, il n’est pas possible de placer des expressions dépendant d’autres arguments :

int k(int a, int b = a);    // interdit

Pour réaliser cette opération, il faut soit placer une valeur par défaut spéciale constante pour b, et recopier a dans b au début de la fonction quand b est égal à cette valeur, soit écrire deux versions de la même fonction, ce qui est permis en C++ (voir plus loin).

Nous utiliserons beaucoup dans la suite ces arguments par défaut, qui permettent de simplifier notablement les programmes, en évitant une surcharge de fonctions.

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