Quand je compile avec clang, j'ai les erreurs suivantes :
prog.cc:21:46: warning: field 'm_arme' will be initialized after field 'm_vie' [-Wreorder-ctor]
Soldat::Soldat(std::string nom) : m_nom(nom),m_arme("Epee"), m_vie(100),m_etat("off")
^~~~~~~~~~~~~~ ~~~~~~~~~~ ~~~~~~~~~~~~~
m_vie(100) m_etat("off") m_arme("Epee")
prog.cc:44:1: warning: non-void function does not return a value [-Wreturn-type]
}
^
prog.cc:49:1: warning: non-void function does not return a value [-Wreturn-type]
}
^
prog.cc:53:1: warning: non-void function does not return a value [-Wreturn-type]
}
^
prog.cc:57:1: warning: non-void function does not return a value [-Wreturn-type]
}
^
prog.cc:58:9: error: C++ requires a type specifier for all declarations
Soldat::afficheEtat()
^
5 warnings and 1 error generated.
Est-ce que tu les comprends et saurait les corriger ?
La première erreur te dit que les champs ne sont pas initialisés dans le même ordre que leur déclaration dans ta classe.
La seconde (et ses copines équivalentes) te dit que ta fonction dit qu'elle renvoie quelque chose mais qu'il manque des return.
La dernière te dit que tu as oublié de donner un type de sortie pour ta fonction afficheEtat.
Merci sa fonctionne maintenant, mais je comprends pas pourquoi la première fois cela avais fonctionné alors que j'avais pas mis de return dans les fonctions.
Ton compilateur doit indiquer les warnings et les erreurs. Il te faut les lire et corriger, tu peux avoir de l'aide sur celles que tu ne comprends pas ou sur comment activer ces warnings si tu ne les vois pas.
Il te reste la fonction afficheEtat() qui s'engage à retourner une std::string, ce qu'elle ne fait pas. Cette fonction ne devrait rien retourner et tu devrais changer son type de retour en void pour indiquer qu'elle ne retourne rien.
Est-ce parce que tu ne comprend pas l'anglais, ou parce que tu ne sais simplement pas comment réagir à ces messages ?
Dans le premier cas, rien ne t'empêche de faire un copier /coller du message dans un traducteur automatique (mais ce serait pas mal que tu apprenne un tout petit peu d'anglais, car tu en aura souvent besoin, d'autant plus que les messages restent écrit dans un anglais "basique" )
Dans le deuxième cas, on va t'aider à comprendre pour cette fois ci
rog.cc:21:46: warning: field 'm_arme' will be initialized after field 'm_vie' [-Wreorder-ctor]
Soldat::Soldat(std::string nom) : m_nom(nom),m_arme("Epee"), m_vie(100),m_etat("off")
^~~~~~~~~~~~~~ ~~~~~~~~~~ ~~~~~~~~~~~~~
m_vie(100) m_etat("off") m_arme("Epee")
Le monsieur t'averti, à la ligne 21; le champs "m_arme" sera initialisé après le champs "m_vie" (parce que les données sont toujours initialisée dans l'ordre de leur déclaration), et que tu as fait le contraire. Il pousse même la gentillesse jusqu'à t'indiquer, sur la troisième ligne, l'ordre dans lequel tu devrais écrire les choses (m_vie en premier, puis m_état, et enfin m_arme).
Ce n'est qu'un avertissement "sans conséquence", mais il est toujours utile de tout corriger (les erreurs et les avertissements) parce qu'il arrive que, les avertissements signalent quelque chose qui n'est pas à proprement une erreur, mais puissent malgré tout changer la manière don ton programme réagit.
prog.cc:44:1: warning: non-void function does not return a value [-Wreturn-type]
}
^
Le problème :
Le monsieur t'avertit qu'il a trouvé à la ligne 44 la fin d'une fonction (l'accolade fermante de la fonction) sans rencontrer l'instruction return alors que cette fonction est censée renvoyer une donnée "non void"
Et pour cause, tu as déclaré la fonction trier comme devant renvoyer une donnée de type std::string.
Voici justement l'un de ces avertissement qu'il faut vraiment corriger, parce que le compilateur va t'obéir et accepter un code qui serait proche de
std::string résultat = trier("salut");
/* on utilise resultat comme on veut ici */
vu que la fonction est censée renvoyer une donnée de type std::string. Seulement, comme la fonction ne renvoie pas de donnée, ben, la variable résultat est -- au mieux -- dans un état "indéterminé". risque donc de fournir des résultats "bizarres".
la solution:
Il faut faire en sorte que la fonction renvoie une donnée du type indiqué qui puisse "avoir du sens" au niveau de la fonction qui a fait appel à celle-ci
(accessoirement, le choix du nom "trier" pour la fonction n'indique absolument pas ce que cette fonction fait car elle n'effectue absolument pas un tri... il serait très utile de choisir un nom de fonction qui corresponde à ce qu'elle fait)
Les trois avertissements qui suivent (concernant les lignes 49, 53 et 57) sont "dans la même veine", avec des causes identiques et donc ... des solutions identiques
prog.cc:58:9: error: C++ requires a type specifier for all declarations
Soldat::afficheEtat()
Voilà enfin l'erreur qui met le compilateur dans un tel état (as tu remarqué? il a utilisé le terme "error" (erreur) ici, alors qu'il avait utilisé le terme "warning" (avertissement) dans les messages précédents).
Le monsieur te dit que C++ implique d'avoir un "type spécifier" (le nom d'un type) pour toutes les déclarations qu'il va rencontrer, et qu'il n'y en a pas à la ligne 59 qui est prend pour l'instant la forme de Soldat::afficheEtat()
Il s'agit en fait d'une définition de fonction. Mais bon, comme une définition a comme résultat de systématiquement déclarer ce qui est défini, cela revient finalement au même que s'il s'agissait d'une "simple" déclaration :D.
Le nom du type que tu dois indiquer correspond au type de donnée que ta fonction est censée renvoyer, et comme c'est obligatoire, si ta fonction n'est pas censée renvoyer quoi que ce soit, il faut l'indiquer explicitement en utilisant le type void (qui signifie littéralement "vide" ou "néant")
Sois cependant attentif au fait que tu as indiqué que ta fonction afficherEtat devait renvoyer le type int à la ligne 12. C'est donc bien le type int que tu dois utiliser ici
Note En Passant: Tiens, as tu remarqué? les avertissements te parlaient de "non-void function". C'est justement à mettre en relation avec le type void dont je viens de parler ici, car le type void pourrait au final être considéré comme un type représentant "l'absence de donnée"'.
Oui, je sais, c'est plutôt "contre intuitif", d'avoir un type représentant ... l'absence de donnée, vu qu'il n'y a justement aucune donnée. Et pourtant c'est comme cela que le compilateur va fonctionner
Pour terminer, un note personnelle:
J'ai l'impression, à la lecture de ton code, que tu es occupé à faire une soupe avec "le type de retour" (la donnée renvoyée par la fonction) et "les paramètres".
Alors, pour faire simple, et éviter tout risque de confusion, prenons une fonction "typique" qui serait proche de
UnType laFonction( UnAutreType leParametre){
/* ce que la fonction fait */
}
Nous sommes ici en face d'une fonction appelée "laFonction" dont on indique au compilateur qu'elle doit renvoyer une donnée de type "UnType" à la fonction qui l'a appelée et qu'elle s'attend à recevoir une donnée -- qui sera connue à l'intérieur de la fonction sous le nom "leParametre" -- qui est de type UnAutreType.
Mais qu'est ce que cela veut dire au final?
Hé bien, cela veut dire que laFonction a besoin d'une information (de type UnAutreType) pour pouvoir faire "son travail" mais que:
elle serait incapable de travailler si elle ne disposait pas de cette donnée
elle n'a pas la possibilité de définir "par elle même" la valeur de cette donnée
elle risque de "travailler différemment" (comprend: de faire des "choses différentes") en fonction de la valeur de cette donnée
la personne qui fait appel à la fonction a la possibilité de modifier le comportement de laFonction à partir de la valeur qu'il décide de fournir pour cette donnée (et qu'il est, normalement, en mesure de déterminer ou de récupérer d'une manière ou d'une autre)
et que, d'un autre coté, une fois que laFonction aura fini son travail, elle pourra renvoyer (ou non, si on utilise le type void) à "celui qui l'a appelée" un résultat de type UnType; et que celui qui a fait appel à la fonction pourra "utiliser à sa guise" la valeur (de type UnType) pour "la suite de son propre travail".
On pourrait donc dire qu'il existe "deux grandes catégories" de fonctions: les fonctions qui posent simplement une question -- et dont la partie "la plus intéressante" (pour celui qui utilise la fonction) est le type de retour -- d'une part et de l'autre les fonctions qui donnent des ordres -- et dont la partie "la plus intéressante" (pour celui qui utilise la fonction) est /sont le (ou les) paramètre(s) qu'il peut transmettre à la fonction afin d'en faire "varier le résultat".
Dans ** certains cas **, "il peut s'avérer utile" de faire en sorte les fonctions qui agissent "comme des ordres" puissent renvoyer (à la personne qui utilise la fonction) quant au résultat de l'exécution de l'ordre en question.
Par exemple, si tu devais avoir une fonction "déplace_toi vers (telle position)" et que tu envisages la possibilité que la position de destination puisse être inaccessible pour une raison ou une autre (peut-être parce qu'elle se trouve au milieu d'un lac, ou dans une pièce fermée dont on n'a pas la clé), il ** pourrait ** "s'avérer intéressant" de faire en sorte que cette fonction renvoie le résultat de l'exécution de cet ordre.
Soit en renvoyant une valeur "vrai ou faux" indiquant simplement "j'ai pu atteindre la position indiquée ou non", soit en renvoyant "la position la plus proche de celle indiquée" que l'on a pu atteindre (et à laquelle on a fini par se retrouver "bloqué"). Le choix dépend de ce que tu veux faire à partir de cette information
Cependant, il arrivera régulièrement que tu fasses comme à l'armée quand on donne un ordre:
si je dis tu saute, (tu cries "chef oui chef" et) tu saute sans poser de questions
C'est, à peine caricaturé, le comportement auquel tu t'attend de la part de tes fonctions trier, changerArme, changeNom et afficheEtat : l'ordre doit être exécuté et sera exécuté quoi qu'il arrive. Il n'y a pas à revenir dessus. Le résultat de cet ordre ne fait donc aucun doute, et tu n'as donc pas besoin d'avoir la moindre confirmation quant à son exécution.
Ce sont donc autant de fonctions qui n'ont absolument aucune raison de renvoyer la moindre information à celui qui l'utilise. Et pour indiquer que la fonction ne va renvoyer "aucune information", le type de retour devrait être void (voir plus haut).
Si tu veux pouvoir poser une question dont la réponse n'a "rien à voir" avec le résultat d'un "ordre donné précédemment" (par exemple: quel est ton nom?) il faut ** forcément ** une fonction différente de celle qui donne un ordre en rapport
- Edité par koala01 17 avril 2022 à 13:50:37
Ce qui se conçoit bien s'énonce clairement. Et les mots pour le dire viennent aisément.Mon nouveau livre : Coder efficacement - Bonnes pratiques et erreurs à éviter (en C++)Avant de faire ce que tu ne pourras défaire, penses à tout ce que tu ne pourras plus faire une fois que tu l'auras fait
Est-ce qu’il y une raison de stocker l'état dans une std::string ? Sans parler du fait que la comparaison n’est pas optimale en terme de performance, c’est surtout que ce n’est pas très clair, si tu veux représenter le fait que l’état a un ensemble de valeurs possibles, tu peux utiliser une enum class. Là si un mec passe l’état "oui" ça ne marchera pas car l’état s’appelle "Oui" (avec une majuscule). L’enum class ne compilerait pas si le mec passe n’importe quoi, ce qui est bien pour éviter ce genre d’erreurs (on n’est pas en javascript profitons-en :-))
Ton compilateur doit indiquer les warnings et les erreurs. Il te faut les lire et corriger, tu peux avoir de l'aide sur celles que tu ne comprends pas ou sur comment activer ces warnings si tu ne les vois pas.
Il te reste la fonction afficheEtat() qui s'engage à retourner une std::string, ce qu'elle ne fait pas. Cette fonction ne devrait rien retourner et tu devrais changer son type de retour en void pour indiquer qu'elle ne retourne rien.
Oui je l'ai mis en void j'avais pas mis le correction avec le void... merci.
J'ai l'impression, à la lecture de ton code, que tu es occupé à faire une soupe avec "le type de retour" (la donnée renvoyée par la fonction) et "les paramètres".
Alors, pour faire simple, et éviter tout risque de confusion, prenons une fonction "typique" qui serait proche de
1
2
3
UnType laFonction( UnAutreType leParametre){
/* ce que la fonction fait */
}
Nous sommes ici en face d'une fonction appelée "laFonction" dont on indique au compilateur qu'elle doit renvoyer une donnée de type "UnType" à la fonction qui l'a appelée et qu'elle s'attend à recevoir une donnée -- qui sera connue à l'intérieur de la fonction sous le nom "leParametre" -- qui est de type UnAutreType.
Mais qu'est ce que cela veut dire au final?
Hé bien, cela veut dire que laFonction a besoin d'une information (de type UnAutreType) pour pouvoir faire "son travail" mais que:
elle serait incapable de travailler si elle ne disposait pas de cette donnée
elle n'a pas la possibilité de définir "par elle même" la valeur de cette donnée
elle risque de "travailler différemment" (comprend: de faire des "choses différentes") en fonction de la valeur de cette donnée
la personne qui fait appel à la fonction a la possibilité de modifier le comportement de laFonction à partir de la valeur qu'il décide de fournir pour cette donnée (et qu'il est, normalement, en mesure de déterminer ou de récupérer d'une manière ou d'une autre)
et que, d'un autre coté, une fois que laFonction aura fini son travail, elle pourra renvoyer (ou non, si on utilise le type void) à "celui qui l'a appelée" un résultat de type UnType; et que celui qui a fait appel à la fonction pourra "utiliser à sa guise" la valeur (de type UnType) pour "la suite de son propre travail".
On pourrait donc dire qu'il existe "deux grandes catégories" de fonctions: les fonctions qui posent simplement une question -- et dont la partie "la plus intéressante" (pour celui qui utilise la fonction) est le type de retour -- d'une part et de l'autre les fonctions qui donnent des ordres -- et dont la partie "la plus intéressante" (pour celui qui utilise la fonction) est /sont le (ou les) paramètre(s) qu'il peut transmettre à la fonction afin d'en faire "varier le résultat".
Dans ** certains cas **, "il peut s'avérer utile" de faire en sorte les fonctions qui agissent "comme des ordres" puissent renvoyer (à la personne qui utilise la fonction) quant au résultat de l'exécution de l'ordre en question.
Par exemple, si tu devais avoir une fonction "déplace_toi vers (telle position)" et que tu envisages la possibilité que la position de destination puisse être inaccessible pour une raison ou une autre (peut-être parce qu'elle se trouve au milieu d'un lac, ou dans une pièce fermée dont on n'a pas la clé), il ** pourrait ** "s'avérer intéressant" de faire en sorte que cette fonction renvoie le résultat de l'exécution de cet ordre.
Soit en renvoyant une valeur "vrai ou faux" indiquant simplement "j'ai pu atteindre la position indiquée ou non", soit en renvoyant "la position la plus proche de celle indiquée" que l'on a pu atteindre (et à laquelle on a fini par se retrouver "bloqué"). Le choix dépend de ce que tu veux faire à partir de cette information
Cependant, il arrivera régulièrement que tu fasses comme à l'armée quand on donne un ordre:
si je dis tu saute, (tu cries "chef oui chef" et) tu saute sans poser de questions
C'est, à peine caricaturé, le comportement auquel tu t'attend de la part de tes fonctions trier, changerArme, changeNom et afficheEtat : l'ordre doit être exécuté et sera exécuté quoi qu'il arrive. Il n'y a pas à revenir dessus. Le résultat de cet ordre ne fait donc aucun doute, et tu n'as donc pas besoin d'avoir la moindre confirmation quant à son exécution.
Ce sont donc autant de fonctions qui n'ont absolument aucune raison de renvoyer la moindre information à celui qui l'utilise. Et pour indiquer que la fonction ne va renvoyer "aucune information", le type de retour devrait être void (voir plus haut).
Si tu veux pouvoir poser une question dont la réponse n'a "rien à voir" avec le résultat d'un "ordre donné précédemment" (par exemple: quel est ton nom?) il faut ** forcément ** une fonction différente de celle qui donne un ordre en rapport
--->
Je n'ai pas compris cette petite note personnelle. J'ai été revoir dans mon bouquin le chapitre des fonction pour voir ce que vous vouliez m'expliquer mais j'ai pourtant bien respecté le retour de la fonction, elle renvois bien à chaque fois des string et une fois un int.
return m_etat renvois un string, return m_nom aussi, ainsi que return m_arme. Ensuite m_vie return bien un int, donc je ne comprend pas trop pourquoi vous dite que je fait une soupe avec le type de retour...
Je vous remercie d'avance, pour vote réponse.
ps : j'ai fais une petite modification j'ai mis en void le type de la fonction que j'avais mis en string et je n'ai rien renvoyé comme valeur de retour est-ce que c'est ce que vous vouliez me signaler dans votre note personnelle ?
Je n'ai pas compris cette petite note personnelle. J'ai été revoir dans mon bouquin le chapitre des fonction pour voir ce que vous vouliez m'expliquer mais j'ai pourtant bien respecté le retour de la fonction, elle renvois bien à chaque fois des string et une fois un int.
Pourrais tu me dire ce que tu n'as pas compris dans cette note personnelle, qui me semble pourtant "si claire"? (mais c'est peut être lié à l'habitude que j'ai de raisonner de la sorte :P)
Ou, qui sait, en la relisant (plusieurs fois au besoin), il se pourrait que tu arrive à comprendre le raisonnement que j'ai suivi, qui est, en gros:
Qu'est ce qui représente une fonction dans le code?
Quels sont les parties "importante" de cette représentation (le type de retour, le nom de la fonction, les paramètres qu'elle s'attend à recevoir lorsque on y fait appel)?
Qu'est ce que cela implique au niveu du code?
Si on essayait de créer différentes "catégories" de fonctions, nous pourrions avoir des "ordres" (fais <quelque chose>) et des questions
Que les fonctions qui agissent comme des ordre peuvent ** éventuellement ** renvoyer une information quant à la possibilité qu'elles ont eu d'obéir à l'ordre donné
Que très souvent, quand la fonction agit comme un ordre, on peut "partir du principe" que cet ordre doit être exécutée et qu'elle le sera de manière systématique
Qu'il est souvent intéressant (voire indispensable) de faire la distinction entre les fonctions qui agissent comme des ordres et celles qui se "contentent" de poser une question (sans que la réponse ne dépende de quelque ordre que ce soit)
Je te laisses trouver à quel endroit de mon intervention commencent les différents points ont été abordés, mais tu remarquera surement que chaque point est introduit de manière "logique", et surtout, traité de manière bien distincte
Ceci étant dit, si une relecture "à tête reposée" ne te suffit pas à comprendre mieux mes explications, n'hésite pas à me dire exactement ce que tu ne comprends pas, je ferai mon possible pour rendre les choses plus faciles à comprendre
Ce qui se conçoit bien s'énonce clairement. Et les mots pour le dire viennent aisément.Mon nouveau livre : Coder efficacement - Bonnes pratiques et erreurs à éviter (en C++)Avant de faire ce que tu ne pourras défaire, penses à tout ce que tu ne pourras plus faire une fois que tu l'auras fait
Ta fonction vie() retourne un int, pourquoi? Si tu n'utilises pas la valeur de retour?
int Soldat::vie(int power)
{
m_vie += power;
return m_vie;
}
//// Et dans le main.cpp, ligne 77
David.vie(100);
Sinon, ta variable Etat n'est pas banale...
.
@koala01 veut te faire comprendre pourquoi et comment utiliser les fonctions. On dirait que tu les utilises conformément a ton cours juste.
Petit test sur la POO
× Après avoir cliqué sur "Répondre" vous serez invité à vous connecter pour que votre message soit publié.
× Attention, ce sujet est très ancien. Le déterrer n'est pas forcément approprié. Nous te conseillons de créer un nouveau sujet pour poser ta question.
Discord NaN. Mon site.
Posez vos questions ou discutez informatique, sur le Discord NaN | Tuto : Preuve de programmes C
En recherche d'emploi.