Programmation • IoT

Chap4 – Les fonctions

Document réservé

Vous consultez actuellement la présentation publique de ce chapitre.

Les documents PDF complets, comprenant les développements théoriques, les exemples détaillés et les exercices, sont disponibles sur demande.

Pour obtenir un accès, contactez-moi via la page Contact en indiquant les domaines qui vous intéressent (C++, ESP-IDF, électronique, etc.).

Chapitre 4 – Les fonctions 4.8 Une fonction peut être appelée plusieurs fois . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4.9 Les fonctions communiquent avec le programme . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4.12 Les fonctions peuvent recevoir plusieurs paramètres . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4.13 Les fonctions qui retournent une valeur . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
Accueil
Chapitre 4 – Les fonctions Chapitre 4 – Les fonction • Comprendre le rôle d’une fonction. • Déclarer et définir une fonction. • Appeler une fonction. • Comprendre les paramètres et les arguments. • Différencier passage par valeur, par référence et par pointeur. • Comprendre l’instruction return. • Écrire des fonctions qui retournent une valeur. • Décomposer un programme en fonctions simples. 4. Instructions conditionnelles 7. Appel de fonction Une fonction est un bloc d’instructions auquel on attribue un nom afin de pouvoir l’utiliser plusieurs fois dans un Au lieu d’écrire plusieurs fois le même morceau de code, on l’écrit une seule fois dans une fonction puis on appelle cette fonction chaque fois que cela est nécessaire. Les fonctions permettent notamment : • d’éviter les répétitions ; • de rendre un programme plus lisible ; • de faciliter les tests et le débogage ; • de construire progressivement des programmes de grande taille.
Accueil
Chapitre 4 – Les fonctions Le langage C++, comme la plupart des langages modernes, est largement fondé sur cette idée de décomposition en Pourquoi les fonctions ? Jusqu’à présent, tous nos programmes étaient relativement courts et tenaient entièrement dans la fonction main(). Cette approche est parfaitement adaptée pour découvrir les différents éléments du langage C++, mais elle atteint rapidement ses limites dès que les programmes deviennent plus importants. Considérons par exemple un programme qui doit gérer les notes d’une classe. Celui-ci pourrait être amené à effectuer les opérations suivantes : • lire les notes des étudiants ; • calculer la moyenne de la classe ; • déterminer la meilleure note ; • afficher les résultats à l’écran ; • enregistrer les données dans un fichier. Écrire toutes ces opérations directement dans la fonction main() rendrait le programme difficile à lire, à comprendre et à modifier. Plus le programme grandit, plus cette difficulté devient importante. Une solution beaucoup plus efficace consiste à décomposer le problème en plusieurs tâches plus simples. Chaque tâche est alors regroupée dans une fonction qui possède un rôle bien précis. • une fonction lit les notes ; • une fonction calcule la moyenne ; • une fonction recherche la meilleure note ; • une fonction affiche les résultats ; • une fonction enregistre les données. Le programme principal devient alors beaucoup plus clair. Il ressemble davantage à une suite d’actions qu’à une longue liste d’instructions. double moyenne = calculerMoyenne(); afficherResultats(moyenne); enregistrerDonnees(); À ce stade, peu importe la manière dont ces fonctions sont écrites. Ce qui est important est de comprendre que chacune d’elles réalise une tâche précise. Cette manière de programmer présente de nombreux avantages : • le programme est plus facile à lire ; • les différentes parties peuvent être testées séparément ; • une modification dans une fonction n’affecte généralement pas les autres ; • une même fonction peut être utilisée plusieurs fois dans un programme.
Accueil
Chapitre 4 – Les fonctions Une fonction peut donc être considérée comme un outil spécialisé auquel on confie une tâche bien définie. En réunissant plusieurs fonctions, il devient possible de construire des programmes beaucoup plus importants tout en conservant une structure claire et facile à maintenir. Une première fonction Nous savons maintenant pourquoi les fonctions sont utiles. Voyons à présent comment en écrire une. La plus petite fonction possible est constituée de trois éléments : • une paire de parenthèses ; • un bloc d’instructions délimité par des accolades. En voici un exemple : À première vue, cette fonction semble ne rien faire. Pourtant, elle est parfaitement valide. Nous venons de définir une fonction nommée bonjour. Examinons chacun des éléments qui la composent. • void indique que la fonction ne retourne aucune valeur. • bonjour est le nom de la fonction. • () indique que la fonction ne reçoit, pour l’instant, aucun paramètre. • {} délimite le corps de la fonction, c’est-à-dire l’ensemble des instructions qui seront exécutées lorsque cette fonction sera appelée. Pour le moment, le corps de la fonction est vide. Nous ajouterons des instructions dans les sections suivantes. Il est important de comprendre qu’une fonction n’est pas exécutée au moment où elle est définie. Sa définition indique simplement au compilateur qu’une nouvelle fonction existe. Pour qu’elle soit exécutée, il faudra l’appeler explicitement depuis une autre partie du programme. Où placer les fonctions ? Dans les exemples de ce chapitre, les fonctions seront définies avant la fonction main(). std::cout << « Bonjour ! » << std::endl; Cette organisation présente un avantage important : lorsque le compilateur lit le programme de haut en bas, il connaît déjà la fonction bonjour() lorsqu’il rencontre son appel dans la fonction main(). Plus loin dans ce chapitre, nous découvrirons qu’il existe une autre manière d’organiser un programme. Pour l’instant, nous placerons donc toujours les fonctions avant main().
Accueil
Chapitre 4 – Les fonctions Appeler une fonction Définir une fonction ne signifie pas qu’elle sera exécutée automatiquement. Une fonction est simplement mise à la disposition du programme. Pour qu’elle soit exécutée, il faut l’appeler. Complétons notre première fonction en lui ajoutant une instruction. std::cout << « Bonjour ! » << std::endl; Cette fonction est maintenant capable d’afficher le message Bonjour !. Cependant, si nous écrivons simplement cette fonction dans un programme, rien ne sera affiché. Considérons le programme suivant. std::cout << « Bonjour ! » << std::endl; Lors de son exécution, ce programme n’affiche absolument rien. Pourquoi ? Tout simplement parce que la fonction bonjour() n’a jamais été appelée. Pour exécuter cette fonction, il suffit d’écrire son nom suivi d’une paire de parenthèses. std::cout << « Bonjour ! » << std::endl; Cette fois, le programme affiche : est appelée un appel de fonction. Lorsque le programme rencontre cette instruction, il interrompt momentanément l’exécution de main(), exécute les instructions contenues dans la fonction bonjour(), puis revient automatiquement à l’instruction suivante.
Accueil
Chapitre 4 – Les fonctions Fig. 1 – Chronologie de l’appel de la fonction bonjour() ci-dessous. • Le programme commence sont exécution dans la fonction main() • Lorsqu’il rencontre l’appel de la fonction bonjour();, il saute vers la définition de la fonction bonjour(). • Il exécute les instructions contenues dans la fonction, càd qu’il affiche Bonjour ! et • il revient dans main() pour poursuivre son exécution. Ici, le programme se termine avec l’instruction return 0 ;. Une fonction peut être appelée plusieurs fois L’un des principaux intérêts d’une fonction est qu’elle peut être utilisée autant de fois que nécessaire. Considérons le programme suivant. std::cout << « Bonjour ! » << std::endl; L’exécution du programme produit le résultat suivant.
Accueil
Chapitre 4 – Les fonctions La fonction bonjour() n’a été écrite qu’une seule fois, mais elle a été exécutée trois fois. Chaque appel provoque une nouvelle exécution de toutes les instructions contenues dans la fonction. Une fonction peut être appelée une seule fois, plusieurs fois ou même jamais. Tout dépend des besoins du programme. • Une fonction est définie une seule fois, mais elle peut être appelée autant de fois que nécessaire. • Chaque appel exécute de nouveau toutes les instructions contenues dans cette fonction. Que va faire le compilateur dans ce cas ? Si le programme s’exécute, que va-t-il se passer ? Quelle va être la Programme 1 – Quiz 1 std::cout << « Bonjour ! » << std::endl; On remarquera que la fonction bonjour() est appelée à l’intérieure d’elle-même ! Les fonctions communiquent avec le programme Notre fonction bonjour() présente toutefois une limitation importante : elle affiche toujours le même message. std::cout << « Bonjour ! » << std::endl; Quel que soit le nombre de fois où cette fonction est appelée, le résultat reste toujours identique. Supposons maintenant que nous souhaitions afficher plusieurs messages différents. Notre fonction actuelle ne permet pas de réaliser cette tâche puisqu’elle ne possède aucun moyen de savoir quel prénom doit être affiché. Pour rendre une fonction plus générale, il faut pouvoir lui transmettre des informations au moment de son appel.
Accueil
Chapitre 4 – Les fonctions Autrement dit, la fonction doit pouvoir communiquer avec le reste du programme. Dans la section suivante, nous allons découvrir le mécanisme utilisé en C++ pour transmettre ces informations à une Le programme ci-dessous compile parfaitement. Comment pourriez-vous le modifier afin qu’il affiche successivement sans écrire trois fonctions différentes ? std::cout << « Bonjour ! » << std::endl; Dans la section précédente, nous avons constaté que notre fonction bonjour() affichait toujours le même message. Pour la rendre plus générale, nous devons pouvoir lui transmettre une information : le prénom de la personne à saluer. En C++, les informations reçues par une fonction sont appelées des paramètres. Modifions notre fonction de la manière suivante. void bonjour(std::string prenom) std::cout << « Bonjour  » <<  » ! » << std::endl; La différence avec la version précédente est la présence de entre les parenthèses. Cette déclaration indique que la fonction reçoit une chaîne de caractères nommée prenom. Cette information pourra être utilisée à l’intérieur de la fonction comme n’importe quelle autre variable. Dans notre exemple, le paramètre est utilisé pour compléter le message affiché. Une fonction peut recevoir aucun, un ou plusieurs paramètres. Nous étudierons les fonctions possédant plusieurs paramètres un peu plus loin dans ce chapitre.
Accueil
Chapitre 4 – Les fonctions Fig. 2 – Paramètre. Déclarer un paramètre dans une fonction ne suffit pas. Il faut également lui fournir une valeur au moment où la fonction est appelée. Cette valeur est appelée un argument. Considérons le programme suivant. void bonjour(std::string prenom) std::cout << « Bonjour  » <<  » ! » << std::endl; L’exécution du programme produit le résultat suivant : À chaque appel de la fonction, une nouvelle valeur est transmise au paramètre prenom. Ainsi, • lors de l’appel bonjour(« Michel »);, le paramètre prenom reçoit la valeur « Michel » ; • lors de l’appel bonjour(« Alice »);, il reçoit la valeur « Alice » ; • lors de l’appel bonjour(« Bob »);, il reçoit la valeur « Bob ». Les paramètres rendent les fonctions beaucoup plus générales. Une seule fonction peut alors effectuer la même opération sur des données différentes simplement en recevant des arguments différents.
Accueil
Chapitre 4 – Les fonctions Lien avec les mathématiques : En mathématiques, on parle très souvent de l’argument d’une fonction, par exemple dans f(x). En programmation, on distingue le paramètre, qui apparaît dans la définition de la fonction, de l’argument, qui est la valeur transmise lors de son appel. Cette distinction permet de décrire plus précisément le fonctionnement Les fonctions peuvent recevoir plusieurs paramètres Jusqu’à présent, les fonctions que nous avons écrites ne recevaient qu’une seule information. Il est toutefois très fréquent qu’une fonction ait besoin de plusieurs données pour effectuer son travail. Considérons, par exemple, une fonction qui calcule l’aire d’un rectangle. Soit le programme complet avec la fonction void aireRectangle(double largeur, double longueur) qui calcule et imprime l’aire du rectangle. void aireRectangle(double largeur, double longueur){ std::cout << « L’aire du rectangle est :  » << largeur∗longueur << std::endl; int main(int argc, const char ∗ argv[]) { aireRectangle(5.0,8.0); Cette fonction possède deux paramètres : Les paramètres sont séparés par des virgules et sont déclarés entre les parenthèses de la fonction. Ils peuvent être de même type, comme dans cet exemple, ou de types différents. void afficherPersonne(std::string nom, int age) <<  » ans. » << std::endl; Le nombre de paramètres n’est pas limité à deux. Une fonction peut recevoir autant de paramètres que nécessaire. Il est cependant recommandé de ne pas en utiliser un trop grand nombre afin de conserver un programme clair et facile à comprendre. Cependant la fonction qui calcule l’aire du rectangle n’est pas satisfaisante car normalement une fonction mathématique retourne une valeur lorsqu’on lui a donné un argument. Notre fonction void aireRectangle(double largeur, double longueur) calcule l’aire certes, mais elle renvoie également une phrase avec la valeur. Cette valeur ne peut pas être réutilisée par le programme. Si l’on souhaite effectuer d’autres calculs avec cette aire, il faut la recalculer, ce qui est peu pratique.
Accueil
Chapitre 4 – Les fonctions Les fonctions qui retournent une valeur Dans la section précédente, notre fonction calculait correctement l’aire d’un rectangle, mais elle affichait directement le résultat à l’écran. Cette solution présente un inconvénient important : une fois la valeur affichée, le programme ne peut plus la réutiliser. Par exemple, il est impossible d’effectuer un autre calcul avec cette aire ou de la mémoriser dans une variable. Il est donc préférable que la fonction renvoie le résultat au programme appelant, qui décidera lui-même de son utilisation. Pour cela, il suffit de remplacer le mot-clé void par le type de la valeur que la fonction doit retourner. Notre fonction double aireRectangle(double largeur, double longueur) return largeur ∗ longueur; Le type double indique que cette fonction retourne un nombre réel. Le mot-clé return termine l’exécution de la fonction et renvoie immédiatement la valeur qui le suit au programme appelant. Dans notre exemple, la valeur retournée est le produit largeur ∗ longueur La fonction ne réalise plus aucun affichage. Elle se contente d’effectuer le calcul et de renvoyer le résultat. double aireRectangle(double largeur, double longueur) return largeur ∗ longueur; double aire = aireRectangle(5.0, 8.0); std::cout << « L’aire vaut  » La valeur retournée par la fonction est ici mémorisée dans la variable aire. Elle pourra ensuite être affichée, utilisée dans un autre calcul ou comparée à une autre valeur. Il est également possible de ne pas utiliser la variable intermédiaire aire et d’écrire simplement double aireRectangle(double largeur, double longueur) return largeur ∗ longueur; std::cout << « L’aire vaut  » << aireRectangle(5.0, 8.0) << std::endl;
Accueil
Chapitre 4 – Les fonctions void doubler(int x) { std::cout << a << « \n »; La réponse est 5, pourquoi ? Le passage par valeur Par défaut, les paramètres d’une fonction sont transmis par valeur. Cela signifie que la fonction reçoit une copie de Considérons le programme suivant. std::cout << a << std::endl; À première vue, on pourrait penser que la variable a vaudra 10 après l’appel de la fonction. Pourtant, ce programme Lorsque la fonction est appelée, la valeur de a est copiée dans le paramètre x. La fonction travaille donc sur une nouvelle variable indépendante de la variable d’origine, et cela même si on écrit.
Accueil
Chapitre 4 – Les fonctions std::cout << a << std::endl; Les deux variables nommées a sont distinctes. Bien qu’elles portent le même nom, les deux variables a sont totalement indépendantes. Chacune possède son propre emplacement en mémoire. Ce mode de transmission est appelé passage par valeur. • Le passage par valeur protège les variables du programme appelant contre toute modification involontaire. Cependant, il existe des situations où l’on souhaite justement modifier la variable transmise à la fonction. Nous allons voir dans la section suivante comment y parvenir. Le passage par référence Dans la section précédente, nous avons vu que le passage par valeur protège la variable d’origine en travaillant sur une copie. Il existe cependant des situations où l’on souhaite que la fonction puisse modifier directement la variable Pour cela, il suffit de déclarer le paramètre comme une référence. void doubler(int& a) std::cout << a << std::endl; Cette fois, le programme affiche La seule différence avec l’exemple précédent est la présence du symbole & devant le paramètre. Ce symbole indique que le paramètre est une référence sur la variable transmise lors de l’appel de la fonction. La fonction ne travaille donc plus sur une copie, mais directement sur la variable d’origine. Toute modification du paramètre est immédiatement visible dans le programme appelant.
Accueil
Chapitre 4 – Les fonctions • Le passage par référence est particulièrement utile lorsqu’une fonction doit modifier une ou plusieurs variables du programme appelant. Il évite également la création d’une copie, ce qui peut améliorer les performances pour les objets volumineux. Les références constituent aujourd’hui la méthode la plus simple et la plus sûre pour permettre à une fonction de modifier une variable. Il existe toutefois une autre technique reposant sur les pointeurs. Bien qu’elle soit un peu plus complexe, elle reste très utilisée, notamment dans certaines bibliothèques et dans les programmes proches du matériel. Le passage par pointeur Comme les références, les pointeurs permettent à une fonction de modifier directement une variable du programme appelant. La différence est que la fonction ne reçoit plus la variable elle-même, mais son adresse mémoire. Considérons le programme suivant. void doubler(int∗ a) std::cout << a << std::endl; L’exécution de ce programme affiche La fonction modifie donc directement la variable a du programme appelant. À première vue, l’utilisation du symbole * peut sembler déroutante puisqu’il apparaît à deux endroits différents : void doubler(int∗ a) Pourtant, ces deux symboles n’ont pas la même signification. Dans la déclaration le symbole * indique simplement que le paramètre a est un pointeur vers un entier. En revanche, dans l’instruction le symbole * signifie :
Accueil
Chapitre 4 – Les fonctions « utiliser la valeur située à l’adresse contenue dans le pointeur ». On dit que le pointeur est déréférencé. Le passage par pointeur fait intervenir deux opérateurs déjà rencontrés dans les chapitres précédents. • &a signifie : « transmettre l’adresse de la variable a » ; • int* a signifie : « recevoir cette adresse dans un pointeur » ; • *a signifie : « accéder à la valeur située à cette adresse ». Ces trois écritures sont donc intimement liées. p est un pointeur vers un entier valeur située à l’adresse contenue dans p Les passages par référence et par pointeur permettent tous deux de modifier la variable d’origine. En C++, on privilégie généralement les références lorsque cela est possible, car leur syntaxe est plus simple et moins sujette aux erreurs. Les pointeurs restent néanmoins indispensables dans de nombreuses situations que nous rencontrerons plus loin dans cet ouvrage. Les prototypes de fonctions Pourquoi utiliser des prototypes ? Jusqu’à présent, toutes les fonctions ont été définies avant la fonction main(). Cette organisation fonctionne parfaitement pour les petits programmes. Lorsque les programmes deviennent plus importants, il est souvent préférable de regrouper les définitions des fonctions à la fin du fichier afin que la fonction main() apparaisse immédiatement. Le programme est alors plus facile à lire et sa structure générale est visible dès les premières lignes. Cependant, lorsqu’il rencontre un appel de fonction, le compilateur doit déjà connaître son existence. Les prototypes permettent de résoudre ce problème. Le programme suivant ne compile pas. std::cout << « Bonjour ! » << std::endl; Au moment où le compilateur rencontre l’appel à bonjour(), il ne connaît pas encore cette fonction. Il suffit alors d’ajouter son prototype avant main().
Accueil
Chapitre 4 – Les fonctions std::cout << « Bonjour ! » << std::endl; Le compilateur connaît maintenant l’existence de la fonction bonjour() avant son appel. Il peut donc vérifier que cet appel est correct et poursuivre la compilation du programme. Qu’est-ce qu’un prototype ? Un prototype est une déclaration qui indique au compilateur qu’une fonction existe. Il précise son nom, son type de retour et la liste de ses paramètres, mais ne contient pas le corps de la fonction. Contrairement à une définition de fonction, un prototype se termine toujours par un point-virgule. Les noms des paramètres sont-ils obligatoires ? Considérons le prototype suivant. double aireRectangle(double largeur, double longueur); La définition de la fonction peut utiliser d’autres noms de paramètres. double aireRectangle(double a, double b) Le programme compile pourtant parfaitement. En effet, le compilateur ne tient compte que du type de retour et des types des paramètres. Les noms des paramètres servent uniquement à rendre le code plus facile à comprendre. C’est d’ailleurs pour cette raison que le prototype peut également s’écrire de la manière suivante. double aireRectangle(double, double); Cette écriture est parfaitement correcte. En pratique, on préfère cependant conserver les noms des paramètres afin de rendre le code plus lisible. • Les prototypes permettent de séparer la déclaration d’une fonction de sa définition. Ils rendent les programmes plus faciles à organiser tout en permettant au compilateur de connaître l’existence des fonctions avant leur utilisation.
Accueil
Chapitre 4 – Les fonctions Dans les projets de grande taille, les prototypes sont généralement placés dans des fichiers d’en-tête (.h ou .hpp), tandis que les définitions des fonctions sont regroupées dans des fichiers sources (.cpp). Nous découvrirons cette organisation dans un chapitre ultérieur. Les paramètres par défaut Pourquoi utiliser des paramètres par défaut ? Il arrive qu’une fonction soit appelée très souvent avec la même valeur pour l’un de ses paramètres. Par exemple, une fonction peut calculer une puissance. Dans la majorité des cas, nous souhaitons simplement calculer le carré d’un nombre. Il serait alors dommage de devoir préciser systématiquement que l’exposant vaut 2. Les paramètres par défaut permettent de définir une valeur qui sera utilisée automatiquement lorsqu’aucune autre valeur n’est fournie lors de l’appel de la fonction. La fonction suivante calcule une puissance. Si aucun exposant n’est précisé, celui-ci vaut automatiquement 2. double puissance(double base, int exposant = 2) return std::pow(base, exposant); std::cout << puissance(5) << std::endl; std::cout << puissance(5, 3) << std::endl; Le programme affiche : Comment cela fonctionne-t-il ? Dans la déclaration de la fonction, indique que le paramètre exposant prendra automatiquement la valeur 2 si aucune autre valeur n’est fournie. Ainsi, les deux appels suivants sont équivalents : utilise la valeur 3, qui remplace la valeur par défaut.
Accueil
Chapitre 4 – Les fonctions Plusieurs paramètres Une fonction peut posséder plusieurs paramètres, dont certains seulement ont une valeur par défaut. void rectangle(int largeur, Les appels suivants sont alors possibles : Dans le premier cas, la hauteur vaut automatiquement 5. Dans le second, elle vaut 10. Une règle importante Les paramètres possédant une valeur par défaut doivent toujours être placés à la fin de la liste des paramètres. Par exemple, cette déclaration est correcte : void rectangle(int largeur, En revanche, celle-ci est interdite : void rectangle(int largeur = 20, Le compilateur ne pourrait plus déterminer correctement la valeur associée à chaque paramètre lors de certains appels. • Les paramètres par défaut permettent de simplifier les appels de fonction lorsqu’une même valeur est utilisée très souvent. Ils évitent de répéter inutilement certaines valeurs tout en laissant la possibilité de les modifier lorsque cela est nécessaire. Les paramètres par défaut offrent une certaine souplesse, mais ils ne permettent pas de répondre à toutes les situations. Il arrive que l’on souhaite définir plusieurs fonctions portant le même nom mais réalisant des traitements différents. C’est le principe de la surcharge des fonctions, que nous allons découvrir dans la section La surcharge des fonctions Pourquoi surcharger une fonction ? Il arrive que plusieurs fonctions réalisent la même tâche, mais avec des types de données différents. Par exemple, nous pourrions souhaiter calculer le carré d’un entier ou celui d’un nombre réel. Les deux fonctions effectuent exactement la même opération. Il serait dommage de devoir leur donner des noms différents. La surcharge des fonctions permet d’utiliser le même nom pour plusieurs fonctions, à condition que leur liste de paramètres soit différente.
Accueil
Chapitre 4 – Les fonctions Considérons les deux fonctions suivantes. double carre(double x) Elles portent le même nom mais leurs paramètres sont différents. Nous pouvons alors écrire : std::cout << carre(5) << std::endl; std::cout << carre(2.5) << std::endl; Le programme affiche : Comment le compilateur choisit-il ? Lorsque le compilateur rencontre l’appel il choisit automatiquement la fonction car l’argument est un entier. En revanche, pour l’appel il sélectionne automatiquement double carre(double x) car l’argument est un nombre réel. Le programmeur utilise donc toujours le même nom de fonction. C’est le compilateur qui choisit automatiquement la version correspondant le mieux aux arguments fournis. Les paramètres doivent être différents Deux fonctions peuvent être surchargées si leur liste de paramètres est différente. Par exemple, les deux fonctions suivantes sont parfaitement valides.
Accueil
Chapitre 4 – Les fonctions int maximum(int a, int b); double maximum(double a, double b); En revanche, les deux déclarations suivantes sont interdites. int maximum(int a, int b); double maximum(int a, int b); Le type de retour ne suffit pas à distinguer deux fonctions. Le compilateur ne tient compte que du nombre et du type des paramètres. Surcharge et paramètres par défaut Dans certains cas, un paramètre par défaut permet d’éviter la création d’une deuxième fonction. Par exemple, au lieu void dessiner(int largeur); void dessiner(int largeur, char caractere); il est possible d’écrire une seule fonction. void dessiner(int largeur, char caractere = ’∗’); Les paramètres par défaut et la surcharge des fonctions sont donc deux mécanismes différents qui permettent de rendre une fonction plus souple. Selon la situation, l’un ou l’autre sera plus approprié. • La surcharge permet de donner le même nom à plusieurs fonctions. • Pour que cela soit possible, les fonctions doivent posséder une liste de paramètres différente. • Le type de retour ne suffit pas à distinguer deux fonctions. Autre exemple de surcharge La fonction valeur absolue. int valeurAbsolue(int x) double valeurAbsolue(double x) Vous vous demandez peut-être comment le compilateur sait quelle fonction appeler. La réponse tient à une caractéristique fondamentale du C++ : c’est un langage fortement typé.
Accueil
Chapitre 4 – Les fonctions Le C++ est un langage fortement typé. Cela signifie que le compilateur connaît le type de chaque variable, de chaque paramètre et de chaque valeur de retour. C’est grâce à cette information qu’il peut distinguer plusieurs fonctions portant le même nom. Lorsqu’une fonction est appelée, le compilateur choisit automatiquement celle dont les paramètres correspondent le mieux aux types des arguments fournis. Tous les langages modernes sont, d’une certaine manière, typés. En revanche, le C++ est généralement présenté comme un langage fortement typé : les types sont au cœur du langage, le compilateur les vérifie rigoureusement et ils influencent directement la résolution des appels de fonctions, la surcharge, les conversions, les templates,
Accueil
cpp-Chap4- Chapitre 4 – Les fonctions
Accueil
Contenu

Inscription

×
Cancel