Nous avons vu quil était possible de déclarer une fonction, ou de la définir entièrement. Lune et lautre opération ne se font que dans la « partie globale » du programme, cest-à-dire à lextérieur de toute autre fonction. Le C++ ne permet pas en effet de créer des fonctions imbriquées comme le Pascal ou dautres langages de programmation.
La syntaxe de la déclaration seule (qui indique le mode d'usage de la fonction) est la suivante :
type_resultat nom_fonction (arguments);
tandis que la définition (qui indique la réalisation effective de la fonction) a la syntaxe suivante :
type_resultat nom_fonction (arguments) { implantation }
Noter labsence de point-virgule dans ce cas.
Nous savons déjà ce que sont les arguments, le nom et le type de résultat de la fonction. Reste à expliquer quel peut être lintérêt de simplement déclarer une fonction, au lieu de la définir complètement.
Lorsque le compilateur rencontre un appel de fonction dans une instruction, il doit déjà avoir rencontré une déclaration de cette fonction (comme pour tout objet de C++ dailleurs) ; cette déclaration, si elle est seule, est souvent appelée prototype de la fonction, car elle permet au compilateur de savoir exactement le type du résultat renvoyé, et celui des arguments ; il peut alors vérifier que les paramètres effectivement passés correspondent aux arguments, ou du moins quils peuvent être transformés en de tels arguments. Dans le cas contraire, il affiche un message derreur signalant la non-concordance des types. Cela renforce considérablement la sécurité décriture des programmes.
En contrepartie, il faut, avant dutiliser une fonction, soit la définir entièrement, soit en donner un prototype (la déclarer). Cela permet notamment de placer les fonctions dans un ordre différent. Par exemple, beaucoup de programmeurs préfèrent placer la fonction main
en début de programme. Il faut alors donner le prototype des autres fonctions avant, comme ceci :
void a(void);void b(void); // fonctions appelées par main main() { a(); b(); ... } int c(void) { // fonction définie entièrement, utilisée par a() } void a(void) { c(); ... } void b(void) { ... }
Une fonction déclarée doit obligatoirement être définie ultérieurement, sinon léditeur de liens proteste (voir chapitre 10). Le prototype de la fonction doit correspondre exactement à la définition, il nest pas permis de changer davis en cours de route :
int f(int a, float x); // prototype // autres... int f(long a, float x) // erreur ! différent du prototype { // implantation }
Cependant, il nest pas nécessaire de donner des noms aux arguments dans le prototype ; la déclaration précédente peut se faire sous la forme :
int f(int, float); // prototype .... int f(int a, float x) // définition { // implantation }
car les noms donnés sont de toute façon ignorés ; ils sont toutefois utiles dans certains cas pour indiquer ce quils signifient :
char *strcpy(char *dest, char *source);
indique clairement dans quel ordre placer les deux chaînes, ce qui est évidemment essentiel dans ce cas.
Les prototypes sont beaucoup utilisés dans les fichiers den-têtes (voir chapitre 10), et dans la récursivité croisée (voir paragraphe sur la récursivité).
Précédent | Sommaire | Suivant |