salut tt monde
je voudrais savoir s il est possible de declarer une fonction au milieu d une autre fonction
salut tt monde
je voudrais savoir s il est possible de declarer une fonction au milieu d une autre fonction
Salut,
Tu peux appeler une fonction au sein de n'importe quelle autre, créer un bloc d'instruction au sein d'un autre, mais, non, tu ne peux ni déclarer ni définir une fonction au sein d'une autre...
Pour information: la déclaration d'une fonction (le fait de dire qu'elle existe) se limite à la fourniture de son prototype ou de sa signature (void mafonct(type arg1); ) et la définition d'une fonction consiste à fournir les instructions qu'elle doit effectuer...
De plus, en C++, seules les fonctions qui ont été valablement déclarées peuvent etre définies (à l'exception de la fonction main, qui est la seule à ne pas devoir etre déclarer et dont l'existance est obligatoire), et toute tentative d'appel d'une fonction déclarée mais non définie se soldera par un échec au niveau de l'édition de liens.
*Typiquement* on sépare les déclarations des définitions, les déclaration dans les fichiers d'entete (*.h), et les définitions dans les fichiers code (*.cpp, *.cxx ...), mais il est possible - bien que ce ne soit vraiment pas recommandé - de mettre les déclarations et les définitions dans le meme fichier.
Il faut alors garder en tete que seules les fonctions qui ont déjà été déclarées pourront etre appelées
Ainsi, ce qui fonctionne sera du genre de:
- un (ou plusieurs) fichier(s) d'entete contenant les déclarations et un (ou plusieurs) fichier(s) contenant les définitions:
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4 dans fichier.h void mafonction(); int ma_deuxieme_fonction(); type ma_troisieme_fontion();
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24 dans fichier.cpp #include "fichier.h" //indispensable pour que le compilateur sache //que les fonctions existent ;) void mafonction() { //... int entier=ma_deuxieme_fonction(); //... type montype=ma_troisieme_fonction(); //... } int ma_deuxieme_fonction() { //... type montype=ma_troisieme_fonction(); //aurait pu etre n'importe quelle fonction ;) //... return (un entier); } type ma_troisieme_fonction() { // peut appeler n'importe quelle fonction valablement déclarée, y compris // celles qui le sont par les inclusions "en cascade" }- La déclaration et leur définition des fonctions dans le meme fichier
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28 // NOTA: dans ce cas, il est préférable de laisser toutes les déclaration // groupée (pour éviter le fait que l'une ou l'autre fonction ne soit pas // connue (déclarée) à un moment donné ;) ) void mafonction(); int ma_deuxieme_fonction(); type ma_troisieme_fontion(); void mafonction() { //... int entier=ma_deuxieme_fonction(); //... type montype=ma_troisieme_fonction(); //... } int ma_deuxieme_fonction() { //... type montype=ma_troisieme_fonction(); //aurait pu etre n'importe quelle fonction ;) //... return (un entier); } type ma_troisieme_fonction() { // peut appeler n'importe quelle fonction valablement déclarée, y compris // celles qui le sont par les inclusions "en cascade" }
Dans les deux cas ci-dessus, l'appel des fonctions fonctionnera sans problème
Ce qui ne fonctionnera pas:
- la déclaration d'une fonction au sein d'une autre
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4 void mafonction() { int mafonction;( int i, int y); }- La définition d'une fonction au sein d'une autre
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11 int mafonction2(); void mafonction { //blabla int mafonction2() { //ce que doit faire mafonction2 } //fin de mafonction }- La définition de fonction non déclarées
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 //déclaration des fonction void mafonction(); void mafonct2(); //définitions de fonctions void mafonction() { //OK } void mafonct2() { //OK } void mafonction3() { //Pas OK, mafonction3 n'a pas été déclarée }- l'appel à une fonction déclarée mais non définie
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14 //déclarations des fonctions void mafonction(); void mafonct2(); void mafonct3(); //définition des fonctions void mafonction() { //appel de mafonct3 qui n'est pas définie mafonct3();//Erreur à l'édition de liens } void mafonct2() { //blabla }
Voici, en condencé et simplifié, les grosses lignes de ce qui peut etre fait et de ce qui ne peut pas etre fait![]()
A méditer: La solution la plus simple est toujours la moins compliquée
Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
Compiler Gcc sous windows avec MinGW
Coder efficacement en C++ : dans les bacs le 17 février 2014
mon tout nouveau blog
En promenant mon chien, deux petites appartés me sont venues à l'esprit:
La premières est le "pourquoi créer une fonction", et la seconde est "mais pourquoi aurait il voulu définir une fonction au milieu d'une autre"...
Alors, commençons par voir pourquoi il est intéressant de créer une fonction (d'un point de vue du programmeur, d'abord, de celui de "l'algorithmique" ensuite)
Du point de vue du programmeur, on va généralement créer une fonction:
- quand on en arrive à plus d'une cinquantaine de lignes dans une meme fonction, et que, pour une raison de pure lisiblité, on préfère en sortir deux fonctions plus petites
- quand une suite d'instructions devra être utilisée à l'identique en de "nombreuses" occasions
- quand on n'a pas le choix (acces en lecture ou en écriture aux membres privés d'une classe, par exemple)
Du point de vue de l'algorithmique, c'est plus simple encore (du moins, à l'écriture): il suffit de garder en tete qu'une fonction ne devrait jamais etre responsable que d'une et une seule chose, mais qu'elle devrait bien le faire...
Evidemment, en dehors du cas où il n'y a pas le choix, il est sans doute un peu excessif de créer une fonction pour "l'incrémentation de a" ou pour l'acces à l'élément suivant dans une liste créée à la main, alors que cela ne tiens qu'à une seule instruction: en toute chose exces est nuisible
Pour la deuxième aparté, sur les quelques minutes qu'a duré la promenade, j'ai vu deux raisons majeurs qui auraient pu t'inciter à trouver un moyen de le faire:
- on estime que la fonction "imbriquée" ne sera utile que dans la fonction dans laquelle tu veux l'imbriquer... mais à ce moment, il faut sérieusement se poser la question de savoir si on en est définitivement sur et certain
- on voudrait autant que faire se peut éviter les phénomenes induits par l'appel d'une fonction, pour une raison de performances, principalement (les push et pop qui précedent et qui suivent l'appel d'une fonction)
Dans le premier cas, on *peut* envisager - mais c'est loin d'être recommandé (je le redis: il faudra etre sur que l'on n'aura pas tendance à appeler la fonction "cachée" ailleurs- de ne déclarer qu'une ou deux fonctions dans un fichier d'entete, et de déclarer la fonction "cachée" dans le fichier d'implémentation:
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3 dans fichier.h void mafonction(); int ma_deuxieme_fonction();Dans le second cas, c'est plus simple encore...
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 dans fichier.cpp #include "fichier.h" void ma_fonction_cachee(); void mafonction() { blabla } void ma_deuxieme_fonction() { blabla } void ma_fonction_cachee() { blabla }
Il "suffit" de déclarer (et de définir) la fonction avec le mot clé inline
inline est un mot clé qui conseille au compilateur de recopier le contenu d'une fonction partout où cette fonction est appelée...
Cela peut rendre les choses bien plus rapides dans le cadre, par exemple, d'une fonction dont le seul but est de renvoyer la valeur d'un membre caché d'une classe.
Par contre, il faut rester conscient du fait que le mot clé inline n'est jamais qu'un conseil fait au compilateur: libre à lui de décider s'il le prendra ou non en compte, avec meme parfois certaines surprises...
Si le compilateur estime "l'inlining" injustifié, il ne l'appliquera simplement pas... Sans compter sur le fait qu'il est, par exemple, incapable de l'appliquer sur les fonctions récursives
Je ne voulais pas écrire un cours dans ce message, et il est déjà dramatiquement long...
Je vous jure pourtant que j'ai essayé de me limiter à certains points de vue et à une explication "de principe", et à le faire le plus simple possible...
Pour de plus amples informations, il ne faudra pas hésiter à poser des questions![]()
A méditer: La solution la plus simple est toujours la moins compliquée
Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
Compiler Gcc sous windows avec MinGW
Coder efficacement en C++ : dans les bacs le 17 février 2014
mon tout nouveau blog
Merci koala01 pour cette réponse
Mais je voulais savoir, ce bout de code n'est-il pas légal ?
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 #include <iostream> void foo(); int main () { foo(); } void foo() { void foo2(); foo2(); } void foo2() { std::cout << "foo2" << std::endl; }
Mathieu
le void foo2(); qui se trouve dans foo() n'est pas légal...
Simplement parce que cela représente la signature de foo2() (sa déclaration, autrement dit)...
En C, il est possible de déclarer une fonction n'importe quand, du moment que c'est en dehors d'une autre, mais je ne suis pas sur que ce soit le cas en C++ (j'ai un doute)...
Ainsi, sont légales:
- d'office
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 void foo(); void foo2(); int main () { foo(); } void foo() { foo2(); } void foo2() { std::cout << "foo2" << std::endl; }- surement en C (et peut etre en C++)
dans le sens où la seule fonction qui aie besoin de connaitre foo2(), c'est foo()
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 void foo(); int main () { foo(); } void foo2(); void foo() { foo2(); } void foo2() { std::cout << "foo2" << std::endl; }
Mais, en tout état de cause foo2 doit etre déclarée
- hors de toute fonction
- Avant la premiere fonction qui y fait appel
(mon doigt a glissé, provoquant l'envoi du message... sorry)
A méditer: La solution la plus simple est toujours la moins compliquée
Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
Compiler Gcc sous windows avec MinGW
Coder efficacement en C++ : dans les bacs le 17 février 2014
mon tout nouveau blog
Partager