Il est parfaitement possible dutiliser des pointeurs sur des fonctions en C++. Il sagit de pointeurs particuliers qui désignent le point dentrée dune fonction dans le programme. On les déclare ainsi :
int (*pf1)(double);long (*pf2)(void);void (*pf3)(int, float);
Le pointeur pf1 est un pointeur sur une fonction ayant un argument double, et de résultat entier. Le pointeur pf2 désigne une fonction sans argument de résultat entier long. Le pointeur pf3 désigne une fonction ayant deux arguments, le premier entier, le second float, et sans résultat.
On notera que du fait de la précédence de lopérateur () sur le déréférencement *, il est obligatoire de placer des parenthèses.
| Exercice 5.4 | Que désignent les écritures suivantes : int *p1(float, int[]); void (*p2)(int (*)(float, float)); long (*) (double[], int) (*p3) (long); |
| Voir solution |
| Exercice 5.5 | Comment déclarer un tableau de pointeurs sur des fonctions renvoyant un |
| Voir solution |
Pour initialiser ces pointeurs, on indique simplement ladresse de la fonction sur laquelle ils pointeront, avec lopérateur dadressage &, comme si cétait de simples variables :
int unefonction(double d);.....int (*pf1)(double) = &unefonction;
Ensuite, on peut appeler la fonction pointée à laide dun déréférencement (même remarque que précédemment à propos de la précédence de () sur *) :
int i = (*pf1)(10.1);
Noter que pour affecter ladresse dune fonction à un pointeur, ladéquation des arguments et du résultat doit être parfaite, et ce jusquaux variantes unsigned ou const. Par exemple, les trois initialisations suivantes seront refusées par le compilateur :
int fonct1(unsigned u);void fonct2(const char *s);float fonct3(void);// ....int (*p1)(int) = &fonct1; // non, incorrectvoid (*p2)(char *s) = &fonct2; // idemdouble (*p3)(void) = &fonct3; // idem
On doit dans ce cas faire un changement de type :
int (*p1)(int) = (int (*)(int)) &fonct1; // okvoid (*p2)(char *s) = (void (*)(char*)) &fonct2; // ok
Le changement de type serait aventureux pour p3, car la promotion de float en double ne sera pas automatique, entraînant des erreurs graves.
En réalité, la plupart des compilateurs se montrent très tolérants vis-à-vis des écritures avec des pointeurs de fonctions, qui sont aussi considérés comme des références. On peut alors écrire :
int i = pf1(10.1);
De même, on peut écrire :
int (*pf1)(double) = unefonction;
Cependant, il ne faut pas supprimer lopérateur * dans cette dernière expression, sinon le compilateur croirait à une définition de fonction.
Les pointeurs de fonctions sont des pointeurs spéciaux, et aucune opération arithmétique nest permise sur eux. Si par exemple on écrit :
pf1++;
le compilateur répond Error : Size of this expression is unknown or zero, la taille de cette expression est inconnue ou nulle, montrant ainsi quil ne peut lui donner un sens, puisquune fonction, au contraire de tout autre type, na pas de taille fixée.
Les déclarations de pointeurs de fonctions seront grandement facilitées en utilisant typedef. Ainsi, voici quelques déclarations :
typedef int pfonc(double);// type pointeur sur fonction(double), de résultat intpfonc pf1 = unefonction;// pointeur sur une telle fonctionpfonc tpf[10] = { unefonction };// tableau de 10 pointeurs de fonctionvoid (*pff)(int, pfonc);// pointeur de fonction sans résultat ayant un int et// un pointeur de fonction pfonc comme arguments Les fonctions peuvent tout à fait avoir un pointeur de fonction comme paramètre ou comme résultat, comme on la déjà vu. Cest même une utilisation fréquente de ces types. Ainsi, on trouve dans la librairie <stdlib.h> une fonction nommée qsort dont len-tête est le suivant :
void qsort(void *base, size_t nelem, size_t largeur, int (*fcomp)(const void*, const void*) );
Cette fonction effectue un tri en utilisant le célèbre algorithme « QuickSort ». Le premier argument base est un pointeur sur le début de la table à trier ; le second est le nombre déléments à trier ; le troisième est la taille en octets de chaque élément ; le dernier est un pointeur sur une fonction qui compare deux éléments, en renvoyant un nombre strictement négatif si le premier est strictement inférieur au second, zéro sils sont égaux, et un nombre strictement positif si le premier est strictement supérieur au second.
| Exercice 5.6 | Écrire un programme qui trie un tableau de 100 entiers, en utilisant |
| Voir solution |
La même librairie contient deux fonctions de recherche, lune bsearch est une recherche dichotomique dans une table triée, lautre lsearch est une recherche linéaire dans une table non triée. Il sagit là dutilisations typiques et très utiles des pointeurs sur des fonctions.
| Suivant |