Pourquoi les fonctions existent
Une fonction est un bloc de code nommé que vous pouvez exécuter à la demande en l'appelant. Au lieu de répéter la même logique à plusieurs endroits, vous l'écrivez une fois, vous lui donnez un nom et vous appelez ce nom partout où vous en avez besoin. Cela rend les programmes plus courts, plus faciles à lire et plus faciles à corriger : modifiez la logique à un seul endroit et tous les appelants reçoivent la mise à jour.
Vous appelez déjà une fonction depuis le début : main. C'est le point d'entrée à partir duquel tout programme C++ démarre. Vous allez maintenant écrire les vôtres. Les boucles que vous avez vues plus tôt, comme la boucle for basée sur une plage, vivent souvent à l'intérieur des fonctions afin que vous puissiez réutiliser tout un morceau de logique par son nom.
Anatomie d'une fonction
Toute fonction comporte quatre parties : un type de retour, un nom, une liste de paramètres entre parenthèses et un corps entre accolades.
int add(int a, int b) { // type de retour | nom | paramètres
return a + b; // corps
}
intest le type de retour : le type de valeur que la fonction renvoie.addest le nom que vous utilisez pour l'appeler.(int a, int b)sont les paramètres : les entrées fournies par l'appelant.- Les accolades contiennent le corps, le code qui s'exécute quand vous l'appelez.
Le voici dans un programme complet. Définir la fonction au-dessus de main signifie que main peut la voir lorsqu'il l'appelle.
L'appel add(2, 3) exécute la fonction avec a = 2 et b = 3, et l'expression entière devient la valeur renvoyée. Vous pouvez la stocker dans une variable ou l'utiliser directement à l'intérieur d'une autre expression, comme le fait la deuxième ligne cout.
Renvoyer une valeur
L'instruction return fait deux choses : elle renvoie une valeur à l'appelant et elle met immédiatement fin à la fonction. Tout code situé après un return ne s'exécute pas : le contrôle revient directement à l'endroit où la fonction a été appelée.
Le type de la valeur renvoyée doit correspondre au type de retour déclaré (ou pouvoir y être converti). Une fonction déclarée int doit renvoyer un int ; ne rien renvoyer, ou sortir par la fin sans return, est un bug pour toute fonction non void.
Fonctions void
Toutes les fonctions ne produisent pas de valeur. Quand une fonction se contente de faire quelque chose (afficher une sortie, mettre à jour un état), son type de retour est void. Une fonction void peut utiliser un simple return; pour sortir plus tôt, ou tout simplement s'exécuter jusqu'à l'accolade fermante.
Essayer d'utiliser le résultat d'une fonction void (int x = greet("Ada");) est une erreur de compilation, car il n'y a aucune valeur à affecter. Une erreur fréquente consiste à écrire return someValue; à l'intérieur d'une fonction void ; le compilateur le rejette aussi.
Déclarations contre définitions
C++ lit un fichier de haut en bas, donc par défaut une fonction doit apparaître avant le code qui l'appelle. Quand cet ordre est gênant, vous séparez la fonction en une déclaration (aussi appelée prototype) et une définition.
Une déclaration énonce la signature de la fonction et se termine par un point-virgule, sans corps. Elle promet au compilateur « cette fonction existe ; voici comment l'appeler ». La définition complète peut alors venir plus tard, même après main.
Sans le prototype à la ligne 4, le compilateur rencontrerait square(5) à l'intérieur de main avant d'avoir jamais vu square, et la compilation échouerait. Les prototypes sont aussi la manière dont les fichiers d'en-tête permettent à de nombreux fichiers source de partager les mêmes fonctions. Notez que les noms des paramètres dans une déclaration sont facultatifs : int square(int); fonctionne tout aussi bien ; seuls les types comptent pour le compilateur.
Erreurs courantes
Quelques pièges attrapent les débutants encore et encore :
- Appeler avant de déclarer. Si vous obtenez une erreur «
addwas not declared in this scope », la fonction est définie sous son premier appel et n'a pas de prototype. Remontez la définition ou ajoutez un prototype. - Oublier de renvoyer. Atteindre la fin d'une fonction non
voidsansreturnest un comportement indéfini : l'appelant reçoit des données indéterminées. Compilez avec les avertissements activés (-Wall) et le compilateur le signalera. - Confondre définir et appeler. Une définition a un corps entre accolades et pas de point-virgule final. Une déclaration a un point-virgule et pas de corps. Les confondre (comme mettre un point-virgule juste après la liste de paramètres d'une fonction que vous vouliez définir) produit des erreurs déroutantes.
- Ignorer la valeur de retour.
add(2, 3);seul sur sa ligne compile, mais la somme calculée est silencieusement jetée. Assurez-vous d'utiliser réellement ce qu'une fonction renvoie.
// On dirait une définition, mais le ; égaré la transforme en une
// déclaration suivie d'un bloc orphelin, une faute de frappe fréquente :
int triple(int n); // <- ce ; termine l'instruction
{
return n * 3; // n n'est pas défini ici ; ce bloc est maintenant orphelin
}
Ensuite : les paramètres de fonction
Vous avez vu les fonctions recevoir des entrées via leur liste de paramètres, mais il y a bien plus à dire. La page suivante creuse les paramètres de fonction : passage par valeur contre passage par référence, arguments par défaut, paramètres const et comment ce choix détermine si votre fonction peut modifier les données de l'appelant.
Questions fréquentes
Comment écrire une fonction en C++ ?
Donnez-lui un type de retour, un nom, des parenthèses pour les paramètres et un corps entre accolades : int add(int a, int b) { return a + b; }. Appelez-la par son nom avec des arguments, comme add(2, 3). Si la fonction ne renvoie rien, utilisez void comme type de retour.
Quelle est la différence entre une déclaration et une définition de fonction en C++ ?
Une déclaration (ou prototype) indique au compilateur le nom, le type de retour et les paramètres d'une fonction, et se termine par un point-virgule : int add(int a, int b);. Une définition fournit en plus le corps entre accolades. Vous pouvez déclarer une fonction avant main et la définir plus tard : la déclaration vous permet de l'appeler avant que la définition n'apparaisse.
Que se passe-t-il si une fonction C++ ne renvoie pas de valeur ?
Pour une fonction void, rien : elle se termine simplement. Mais pour une fonction non void, atteindre la fin sans return est un comportement indéfini : l'appelant reçoit une valeur indéterminée et le programme peut mal se comporter. La plupart des compilateurs vous avertissent ; renvoyez toujours une valeur sur chaque chemin d'une fonction non void.