Incompréhension totale SFML et principes de base
[Dal] Messages postés 6194 Date d'inscription mercredi 15 septembre 2004 Statut Contributeur Dernière intervention 11 octobre 2024 - 9 janv. 2024 à 19:23
- Incompréhension totale SFML et principes de base
- Formules excel de base - Guide
- Base de registre - Guide
- #1046 - aucune base n'a été sélectionnée - Forum MySQL
- Formules mathématiques de base - Télécharger - Études & Formations
- Gigaset as470h base ✓ - Forum telephonie fixe
2 réponses
Modifié le 7 janv. 2024 à 21:15
Salut,
Plutôt que de poster des images, poste du code.
Ton module (tu devrais l'appeler autrement que "Main.cc" et "Main.h", par exemple "handler.cc" et "handler.h"), comprend un fichier .cc avec l'implémentation et un fichier .h avec les déclarations des fonctions et les includes nécessaires à la compilation du fichier .h et du fichier .cc.
Disons donc que ton module s'appelle "handler".
La première ligne du code .cc de ton module devrait comporter un #include "handler.h"
Tu peux aussi remettre dans le .cc les includes utilisés par l'implémentation, même s'ils sont déjà inclus avec le include du header du module.
Tu devrais lire aussi ceci :
https://websites.umich.edu/~eecs381/handouts/CppHeaderFileGuidelines.pdf
Cela va t'aider à comprendre de façon plus globale ce que tu devrais mettre dans tes fichiers .cc et tes fichiers .h.
Ensuite, pour utiliser ton module, il te faudra un fichier .cc incluant "handler.h". Par exemple, ton fichier .cc comprenant une fonction main(), que tu pourras appeler main.cc comme il se doit :-)
Modifié le 9 janv. 2024 à 03:09
Bonjour,
Préliminaires
Comme le dit fort justement Dal, partage ton code comme expliqué ici. Essaye de et de soigner l'orthographe (j'ai corrigé ton message initial). Essaye aussi d'être concis pour augmenter tes chances d'être lu et donc aidé. Comme ton message est long, ma réponse sera longue :-)
Réponse courte
À ce stade ton programme ne compile pas. Du coup, impossible de tirer des conclusions. Fais déjà en sorte que ton programme compile (pour cela il faut comprendre les messages d'erreur, et ce qui suit t'y aidera peut-être).
Ensuite, comme le dit [Dal], si tu veux des réponses plus précises (par exemple qu'on corrige tes erreurs de compilations), il faudrait nous partager le code source correctement et idéalement nous dire comment tu compiles ton projet. Beaucoup d'erreurs parmi celles affichées concernent du code qui n'est pas affiché dans tes captures d'écran.
Réponse détaillée :
Concernant ton introduction
Première point, il faut que tu comprennes comment est organisé un projet en C++.
Sous sa forme la plus simple on a un fichier ".cpp" (ou ".cc") qui contient une fonction main. Mais rapidement, ce fichier devient énorme et on fait des modules. Toi tu parles d'un module (fonction.{hpp, cpp}) mais dans un projet réaliste il y en a bien plus, et typiquement un par fenêtre. Mais souvent, un ".cpp" a besoin de fonctions/classes/... provenant d'autres modules. C'est là que les ".hpp" entre en jeu : ils exposent au reste du monde ce qui est dans le ".cpp" correspondant.
Quand on compile un projet, on commence par résoudre toutes les instructions qui commencent par un #. Le précompilateur ne sait faire que des tâches basiques (remplacer un variable définie par un #define par sa valeur, connue de fait avant la compilation ; copier coller le contenu d'un fichier dans un autre avec un #include ; etc.). C'est la précompilation.
Quand un fichier ".cpp" est précompilé, on peut le compiler. Chaque ".cpp" engendre à terme un ".o" une fois compilé. Chaque module est compilé dans un ordre arbitraire (voire ils sont compilés en parallèle). À ce stade, les ".hpp" sont juste là pour dire au compilateur qu'à terme (plus précisément, au linkage), il aura un (autre) binaire qui implémentera ces fonctions/classes externes. La production des .o correspond à la compilation.
Maintenant arrive l'heure des compte. Chaque symbole (fonction, classe) annoncé doit être implémenté une et une seule fois.
- C'est la raison pour laquelle un symbole n'est jamais implémenté dans un ".hpp" (car sinon, il serait "dupliqué" dans tous les ".o" engendré par les ".cpp" qui utilisent ce ".hpp").
- Dans la même veine, c'est également la raison pour laquelle on met des gardes dans les .hpp (voir exemple ci-dessous) : si c.cpp inclue a.hpp et b.hpp, et que b.cpp include b.hpp et a.hpp, tu ne veux pas que les symboles de a.hpp soient à la fois dans c.o et b.o
/* c.hpp */ #ifndef C_HPP #define C_HPP #include "a.hpp" #include "b.hpp" void c(); #endif
/* b.hpp */ #ifndef B_HPP #define B_HPP #include "a.hpp" void b(); #endif
/* a.hpp */ #ifndef A_HPP #define A_HPP void a1(); void a2(); #endif
/* c.cpp */ void c() { a1(); b(); }
- Cela inclue tes propres symboles, mais plus généralement tous ceux que tu utilisent (dont ceux dans SFML). Et c'est pourquoi à l'heure des compte, il faut non seulement avoir tous tes ".o", mais aussi tous les ".so"/".dll" des librairies tierces que tu utilises.
Si chaque symbole est bien trouvé une et une seule fois, on peut produire un binaire. Cette étape est appelée le linkage. Le linkage produit :
- soit un exécutable (".exe" sous windows, sans extension sous Linux),
- soit une librairie
- dynamique ( ".dll" sous Windows et un ".so" sous Linux)
- statique (".lib" sous Windows, ".a" sous Linux)
- soit un objet noyau (".ko" sous Linux)
Maintenant que nous avons vu la compilation, passons à comment organiser un projet.
Tu t'en doutes le nombre de module augmente assez rapidement dans un projet, et compiler un par un chacun de ces modules manuellement va rapidement être fastidieux. On va donc s'empresser d'automatiser tout ça.
Si ton IDE est bien configuré et que ton projet est bien défini, il suffira de cliquer sur un bouton pour que tout se fasse tout seul. Quand on redistribue son programme toutefois, on peut difficilement espérer que les autres utilisent le même environnement de développement. Donc, pour bien faire les choses, on livre le projet avec un script de compilation (typiquement un Makefile).
Cependant, le Makefile dépend du système d'exploitation et de la manière dont les libraries (par exemple SFML) ont été installées. Donc en toute rigueur, on n'écrit pas soi-même ce fichier, on le fait générer à partir d'un outil tiers (typiquement cmake) qui lui prendra en compte toutes ces considération.
Quoi qu'il en soit si tu as un Makefile, il est poli de le joindre, ne serait ce que pour qu'on sache avec quelles librairies de SFML tu linkes.
Deuxième point, un peu hors sujet, sache qu'il existe de nombreuses autres librairies graphiques libres et bien plus utilisées (par exemple GTK et Qt, et dans une moindre mesure SDL). Tu es parfaitement libre d'utiliser SFML si c'est la librairie que tu aimes et je ne chercherai pas à te faire changer d'avis, mais à mon humble avis, il est plus stratégique d'utiliser des librairies répandues (tu valoriseras plus facilement ton profil, pourra rentrer plus facilement dans des projets les utilisant, etc.).
Troisième point, tu dis que tu t'attends à ce que faire deux fois la même chose donne deux fois le même résultat. Eh bien attends toi à être déçu, car si ton programme comporte des erreurs mémoire, son comportement est le plus souvent une erreur de segmentation, mais dans le cas général, son comportement est imprévisible (en tout cas, non déterministe). En résumé, en C/C++ quand un programme plante, tu sais qu'il est faux. Quand il fonctionne il est peut être correct, et en toute rigueur, pour s'en assurer, il faut vérifier que tout est OK côté mémoire avec des outils comme valgrind.
Concernant ton problème
D'après tes captures d'écran, ton projet ne semble pas compiler. Ce qui laisse penser que des ".o" résiduels traînent et ne reflètent pas réellement l'état de ton code.
Il n'y a pas vraiment d'intérêt à déclarer dans un .h une fonction f qui est dans ton main.cpp :
- soit f est implémentée dans main.cpp n'est utilisé que dans main.cpp, et c'est inutile (à moins qu'elle ne soit utilisée dans une fonction g déclarée avant f) ;
- soit f est utilisée ailleurs que dans main.cpp et là tu risques d'avoir de gros problème au moment du linkage, car ça veut dire que si tu commences à avoir un main.hpp (très mauvaise idée) tu vas rapidement avoir des inclusions circulaires.
La bonne stratégie, c'est d'avoir dès le début un main.cpp minimal, et à chaque fois que le besoin s'en fait sentir, de créer un nouveau module (.hpp + .cpp). Cette étape consiste donc à "bien découper" le problème auquel ton programme s'attaque en objet cohérents. C'est là qu'arrive la programmation objet et des notions telles que l'UML.
Bonne chance
9 janv. 2024 à 19:23
tes gardes dans le fichier .h doivent aussi débuter à la première ligne, et pas après les includes.