Partage
  • Partager sur Facebook
  • Partager sur Twitter

Définir des paramètres à l'éxecution du programme

    5 juin 2020 à 13:08:11

    Bonjour,

    Dans le cadre de ma thèse en physique théorique, j'ai réalisé un programme qui résout un système d'équations différentielles couplées (non-linéaires) avec des conditions aux bords. Je vous passe les détails physiques mais en bref, ce sont les équations de champs d'une théorie de gravitation massive qui contiennent divers paramètres. Ces paramètres restent constants pendant toute l'exécution du programme, mais le but est de résoudre les équations pour pleins de valeurs afin d'explorer l'espace des paramètres.

    Pour le moment, je définissais donc mes paramètres avec des commandes pré-processeur :

    #define c3 1.0
    #define c4 -1.0
    #define m 0.025

    que je mets dans un de mes header. J'ai découpé mon code en trois parties : un main.cpp, une partie routines.cpp, routines.h (qui contient mes routines d'intégration numérique), et une partie functions.cpp, functions.h (qui contient les équations à proprement parler, issues de Mathematica et converties en langage C++). Cette dernière partie est extrêmement longue (17000 lignes) et donc la compilation prend quelques minutes (je compile avec un MakeFile).

    Mon problème est que puisque mes paramètres sont dans des #define, je dois recompiler entièrement le code si je veux les faire varier ce qui me fait perdre assez de temps à chaque fois. Ce que je voudrais faire c'est écrire les paramètres dans un fichier "input" qui est lu dans par le main au début de l'exécution ; et il faudrait que les constantes lues soient ensuite accessibles par tout le reste de mon programme, sans devoir les passer en paramètres de toutes mes fonctions. Je trouve en effet cela très rébarbatif de devoir passer par les paramètres de mes fonctions car ces constantes de la théorie sont fixées une bonne fois pour toute, dans le reste du code.

    Comment faire cela proprement ? J'avais pensé naïvement à déclarer des variables globales dans un de mes header mais le problème c'est que ça fait des définitions multiples puisque les fichiers .h sont inclus dans les trois fichiers .cpp ...

    Merci d'avance pour votre aide, j'espère avoir été assez clair dans mes explications.

    • Partager sur Facebook
    • Partager sur Twitter
      5 juin 2020 à 13:26:13

      Salut ! As-tu déjà entendu parlé de tests unitaires ? A partir du moment ou ton programme n'est pas hyper conséquent la technique edit-compile-debug fonctionne, mais il est certain qu'avec un projet de plus grande envergure ça devient gênant, et c'est là ou les tests unitaires doivent être utilisés. Je te laisse te documenter avec la doc Microsoft mais il existe des tas d'explications sur internet et tu es libre de t'instruire.

      Sinon, les constantes définies par des directives préprocesseur c'est pas beau, ça a même été une des raisons qui a poussé à la création des modules en C++20... en C++ on utilisera des expressions constantes qui sont évaluées durant la compilation (si contraintes respectées). Par exemple:

      // Au lieu de:
      namespace constantes {
        #define c3 1.0
        #define c4 -1.0
        #define m 0.025
      }
      /*
       * Il y a un risque de collision... l'espace de nom "n'isole" pas les constantes définies par #define.
       */
      
      // On fait:
      namespace constantes {
        constexpr double c3 {  1.0 };
        constexpr double c4 { -1.0 };
        constexpr double m { 0.025 };
      }
      /*
       * Plus de risque de collision. Les variables sont "isolées" dans l'espace de nom.
       */

      Il existe plus d'une façon de définir des constantes dans le langage. Les constexpr(s) ne sont qu'une solution sur toutes celles qui existent. J'aurais très bien pu avoir le même résultat en décidant de créer une structure qui possède des membres statiques qu'on utiliserait comme des constantes. Exemple:

      struct constantes {
        constantes() = delete;
        // On supprime le ctor pour empêcher l'instanciation.
        constantes( const constantes& ) = delete;
        // On supprime de copy ctor pour empêcher la copie.
      
        static double c1;
        static double c4;
        static double  m;
      };
      
      // On est obligés de définir les membres statiques en
      // dehors de la déclaration de la structure.
      double constantes::c1 =   1.0;
      double constantes::c4 =  -1.0;
      double constantes::m  = 0.025;

       =====

      Un dernier mot, si tu souhaites que ton application soit disponible sur le plus d'environnement possible, pour pouvoir l'utiliser autant avec un Makefile qu'avec l'IDE Visual Studio ou Code::Blocks tu devrais utiliser cmake. C'est simple à utiliser, et ça ajoute une certaine portabilité à ton programme.

      -
      Edité par Daimyo_ 5 juin 2020 à 13:43:21

      • Partager sur Facebook
      • Partager sur Twitter
        5 juin 2020 à 13:57:35

        Salut,

        Tu nous parles de paramètres et de constantes, ce sont deux concepts qui par nature sont incompatible (un paramètre est supposé changer, alors qu'une constante non).

        Tu n'as pas vraiment le choix, il va te falloir introduire des variables afin de mémoriser tes paramètres quelque part.
        Je laisse la technique à utiliser (ligne de commande, fichiers, saisie utilisateur ect …) à ton appréciation.

        Quand à l'utilisation de variables globales, c'est une idée qui n'aurait même pas du germer dans ton esprit. Cela dénote une erreur de conception dans ton architecture.
        Et si tu as peur de te retrouver avec une multiplication incontrôlée de variables, encapsule les dans une classe, c'est fait pour ca.

        • Partager sur Facebook
        • Partager sur Twitter
          5 juin 2020 à 14:23:34

          Daimyo_ a écrit:

          Salut ! As-tu déjà entendu parlé de tests unitaires ? A partir du moment ou ton programme n'est pas hyper conséquent la technique edit-compile-debug fonctionne, mais il est certain qu'avec un projet de plus grande envergure ça devient gênant, et c'est là ou les tests unitaires doivent être utilisés. Je te laisse te documenter avec la doc Microsoft mais il existe des tas d'explications sur internet et tu es libre de t'instruire.

          Sinon, les constantes définies par des directives préprocesseur c'est pas beau, ça a même été une des raisons qui a poussé à la création des modules en C++20... en C++ on utilisera des expressions constantes qui sont évaluées durant la compilation (si contraintes respectées). Par exemple:

          // Au lieu de:
          namespace constantes {
            #define c3 1.0
            #define c4 -1.0
            #define m 0.025
          }
          /*
           * Il y a un risque de collision... l'espace de nom "n'isole" pas les constantes définies par #define.
           */
          
          // On fait:
          namespace constantes {
            constexpr double c3 {  1.0 };
            constexpr double c4 { -1.0 };
            constexpr double m { 0.025 };
          }
          /*
           * Plus de risque de collision. Les variables sont "isolées" dans l'espace de nom.
           */

          Il existe plus d'une façon de définir des constantes dans le langage. Les constexpr(s) ne sont qu'une solution sur toutes celles qui existent. J'aurais très bien pu avoir le même résultat en décidant de créer une structure qui possède des membres statiques qu'on utiliserait comme des constantes. Exemple:

          struct constantes {
            constantes() = delete;
            // On supprime le ctor pour empêcher l'instanciation.
            constantes( const constantes& ) = delete;
            // On supprime de copy ctor pour empêcher la copie.
          
            static double c1;
            static double c4;
            static double  m;
          };
          
          // On est obligés de définir les membres statiques en
          // dehors de la déclaration de la structure.
          double constantes::c1 =   1.0;
          double constantes::c4 =  -1.0;
          double constantes::m  = 0.025;

           =====

          Un dernier mot, si tu souhaites que ton application soit disponible sur le plus d'environnement possible, pour pouvoir l'utiliser autant avec un Makefile qu'avec l'IDE Visual Studio ou Code::Blocks tu devrais utiliser cmake. C'est simple à utiliser, et ça ajoute une certaine portabilité à ton programme.

          -
          Edité par Daimyo_ il y a 21 minutes


          Super merci, je pense que je vais pouvoir me débrouiller avec les structures. (Je suis plus physicien que développeur, j'avoue que j'avais oublié ces histoires de structures et membres statiques).

          @Deedolith : Quand je parle de "paramètres" c'est du point de vue de la théorie physique que j'étudie, pas de l'informatique. Le mot correct du point de vue de mon programme est effectivement "constante" car elle est fixée pendant toute l'exécution. Du point de vue de la physique, ces "constantes", sont à prendre au même titre que la vitesse de la lumière, la masse de Planck, la constante gravitationnelle, etc...Sauf que pour toutes celles que je viens de te citer, on connaît leur valeur depuis longtemps avec beaucoup de précision ; les "constantes" de la théorie que j'étudie ne sont pas connues, on a aucune idée de ce qu'elles peuvent valoir, c'est pour ça que je veux pouvoir les faire varier en input de mon programme. Mais ensuite, encore une fois, pendant toute l'exécution de mon programme, elles ne bougent pas. Bref, désolé d'avoir mélangé le jargon de la physique avec celui de l'informatique. Quoiqu'il en soit je pense que je vais utiliser les structures plutôt que les classes, je pense qu'utiliser une classe c'est un peu sortir l'artillerie lourde pour quelque chose de simple.

          • Partager sur Facebook
          • Partager sur Twitter
            5 juin 2020 à 14:47:01

            > Je pense qu'utiliser une classe c'est un peu sortir l'artillerie lourde pour quelque chose de simple

            C'est relatif à toi même. Personnellement je suis beaucoup plus "orienté objet" que "style C", j'aurais certainement défini une classe simple, mais c'est mon avis.

            Ne t'attarde pas trop sur les détails de développeur, ça te fait perdre beaucoup de temps. J'ai presque envie de dire "du moment que ça tourne comme tu veux ça va.". Je pense que le but ici c'est surtout d'être efficace et clair et partir dans un débat de conception logiciel c'est loin d'être le but d'un physicien, je suppose...

            Il y a un sacré creux entre la relativité restreinte (désolé, aucune autre ref xD) et l'orienté objet: Un développeur se fiche de savoir ce qu'est l'espace temps tout comme un physicien se fiche de savoir s'il faut utiliser des objets et des classes ou tout faire en fonctionnel. Bien que le physicien doivent probablement travailler en étroite collaboration avec des développeurs, je ne pense pas qu'il s'occupe de la partie conception du programme, sinon les programmes super-puissants qui simulent la mécanique des fluides seraient à chier xD.

            Bref... regarde bien les tests unitaires, ça t'empêchera d'avoir à recompiler tout le projet à chaque fois que tu veux déboguer ou tester.

            • Partager sur Facebook
            • Partager sur Twitter
              5 juin 2020 à 15:27:55

              >je vais utiliser les structures plutôt que les classes, je pense qu'utiliser une classe

              Ne confondez pas les structures du C et les structures du C++.
              Une structure C++ EST une classe !!!
              Donc utilisez une classe (c'est plus simple).

              Vous analysez votre problème comme une taupe. (non offense)
              Il faut voir un peu plus à "long" terme.

              Dans votre "théorie physique", c'est des constantes, mais là, vous êtes en train de faire une exploration des valeurs possibles, ce qui en fait des variables/paramètres de l'exploration.
              Vous vous leurrez à vouloir en faire des constantes durant une exécution, mais vous négligez complètement les problématiques de performance comme le coup énorme de démarrage d'un processus, la perte des calculs intermédiaires très probable, la non intégration dans les framework de calcul massifs comme map/reduce (Hadoop), etc...
              En les utilisant vraiment comme des variables et donc à prendre la peine d'utiliser les mécanismes de passage des valeurs de module/fonction/instance, vous aurez des possibilités d'évolution mais aussi et surtout un code bien plus clair.
              Un simple paramètre "contexte" pour chaque procédure ou objet ayant besoin de ces valeurs serait largement suffisant.
              Votre programme n'est pas un "monde simulé" mais un outil pour répondre à des questions.

              -
              Edité par bacelar 5 juin 2020 à 18:10:36

              • Partager sur Facebook
              • Partager sur Twitter
              Je recherche un CDI/CDD/mission freelance comme Architecte Logiciel/ Expert Technique sur technologies Microsoft.
                5 juin 2020 à 15:50:12

                > Ne confondez pas les structures du C et les structures du C++. Une structure C++ EST une classe !!!

                D'un point de vue syntaxique, oui les classes sont très similaires aux structures, la seule petite différence c'est la portée des membres "par défaut": une classe possède par défaut une portée privée, et une structure possède par défaut une portée publique.

                Sauf qu'une grande partie des programmeurs C++ distinguent ces deux structures de données de façon concrète: Les structure servent exclusivement comme structure de données, et seulement de données et les classes servent de structures de données et d'opérations qui ont un impact sur l'état de ces données (sauf si conception particulière).

                > Donc utilisez une classe (c'est plus simple).

                Si on suit cette logique, alors une structure serait plus appropriée. D'ailleurs, la portée publique des structures offre une façon simple d'accéder à ses données, par besoin d'encapsuler ou quoi que ce soit, c'est du temps de réflection en moins sur un sujet qui n'a pas a être traité par un physicien ça rend les choses plus efficace POUR LUI.

                Mais on peut passer des heures à discuter de "classe ou structure ?", ça dépend surtout de ta façon de programmer et d'interpréter l'utilité des deux structures de données. En fin de compte, c'est personnel, comme pour beaucoup de choses dans le domaine.

                Sinon, @bacelar, je suis d'accord avec toi pour le reste.

                -
                Edité par Daimyo_ 5 juin 2020 à 15:51:40

                • Partager sur Facebook
                • Partager sur Twitter
                  5 juin 2020 à 17:12:18

                  @Daimyo_, tu n'as toujours pas fait le deuil du C, gars.

                  La définition de ce qu'est une structure C++ est clairement indiquée dans la norme C++ et t'as manière de l'interpréter n'est qu'une nostalgie (directe ou par procuration via un enseignement peu renouvelé) du C.

                  (Je ne dis pas que ce que tu dis est faux d'un point de vue historique, mais dans les faits, actuellement, c'est la définition qui compte)

                  • Partager sur Facebook
                  • Partager sur Twitter
                  Je recherche un CDI/CDD/mission freelance comme Architecte Logiciel/ Expert Technique sur technologies Microsoft.
                    5 juin 2020 à 17:34:14

                    @bacelar : Mais on est d'accord que la portée d'une classe est par défaut privée alors que pour une structure c'est publique ? Si je veux accéder aux attributs d'une classe il faut utiliser un accesseur, etc... Tout ce principe d'encapsulation, tandis que pour une structure c'est publique. Pour moi une classe c'est un truc puissant qui combine des attributs, des méthodes réalisant des opérations. Qui peut le plus peut le moins, oui on peut faire avec une classe ce que je fait avec les structures, mais personnellement je vois pas l'utilité d'utiliser une classe (ce qui m'obligerait à faire de l'encapsulation) alors que je n'ai aucune méthode à implémenter dedans. Je veux juste pouvoir accéder facilement à mes paramètres.

                    Sinon ok, j'ai compris que c'était pas bien les #define :euh:.

                    • Partager sur Facebook
                    • Partager sur Twitter
                      5 juin 2020 à 17:42:02

                      Tu n'as pas compris mes explications. je n'ai jamais programmé en C, je ne connais pas le langage, mon "deuil" pour le C n'en est pas un. Par contre je sais que les programmeurs C++ ont tendance à se servir des structures comme de simple structures de données, en particulier comme structure particulière en tant que type de retour d'une fonction, ou alors comme "classe" de traits. Qu'une structure ait les même fonctionnalités qu'une classe, oui, mais tu ne trouveras que très rarement des codes dans lesquels les structures sont utilisées comme des classes.

                      Donc mon exemple avec les variables statiques est valide pour toi ? @bacelar a raison à propos du fait que tu ne simules pas un environnement physique mais que tu cherches à répondre à des questions. Utiliser des données constantes alors que tu les modifies régulièrement c'est paradoxal. Juste question "lecture du code", il serait plus logique de créer des données non-constantes pour comprendre la démarche de recherche d'une certaine valeur.

                      Bon on est de plus en plus du côté conception... C'est pas bien ça :D

                      -
                      Edité par Daimyo_ 5 juin 2020 à 18:17:09

                      • Partager sur Facebook
                      • Partager sur Twitter
                        5 juin 2020 à 18:44:58

                        >Mais on est d'accord que la portée d'une classe est par défaut privée

                        Attention à ne pas confondre accessibilité et portée qui sont des notions bien différentes.

                        >Si je veux accéder aux attributs d'une classe il faut utiliser un accesseur

                        Non, il suffit de les déclarer dans une partie "public" de la définition de la classe.

                        Vous voyez une structure C++ comme si c'était une structure C, ce qui n'est pas le cas.

                        Vous pouvez (et devez, si nécessaire) définir des fonctions ou des attributs privées à une structure C++.

                        Vous faites une séparation complète entre structure C++ et classe C+ alors que c'est quasiment la même chose.

                        >tandis que pour une structure c'est publique

                        NON, c'est publique PAR DÉFAUT !!!

                        >je vois pas l'utilité d'utiliser une classe (ce qui m'obligerait à faire de l'encapsulation)

                        Non, vous n'êtes pas obligé.

                        >Je veux juste pouvoir accéder facilement à mes paramètres.

                        C'est la même chose avec une classe ou une structure, les champs peuvent être publics.

                        Mais tout ceci n'est qu'un débat assez stérile, car classe et structure, c'est quasiment la même chose en C++.

                        Bon, je joue un peu à la pédagogie du "marteau" : casser les mauvaises habitudes de penser qui bloquent l'analyse "correct" des problématiques à résoudre.

                        Il peut être plus pertinent, si les performances ne sont pas très importantes et que l'espace de recherche n'est pas très grand, de "payer" de multiples démarrage de processus avec un paramétrage en ligne de commande ou en fichier de configuration et utilisation de "Singleton"/Variables Globales, si le code généré existant est déjà très important.

                        Mais cette approche ferme énormément de voies d'amélioration donc c'est un gain à très court terme.

                        Si l'utilisation d'un paramétrage "contexte" est facilement et rapidement faisable : c'est un "quick win". Vous avez une solution rapidement et qui pourra facilement évoluer.

                        Le plus important, c'est de bien analyse le problème à résoudre et pas plaquer une modélisation figée de "l'Univers" lors de l'analyse : vos constantes inconnues physiques ne sont pas des constantes dans le cadre de votre problématique d'exploration dans leurs domaines de validité.

                        Vous avez eu le bon réflexe de ne pas vous contenter de votre "solution" qui fonctionne au coût d'un travail de recompilation de força, mais avec un peu de recul, vous pourrez vous servir "d'outils standards" de calculs parallèles pour explorer efficacement ces domaines de validité.

                        Mais pour cela, il faut prendre un peu de temps pour analyser le "vrai" problème à résoudre.

                        @Daimyo_, votre constatation n'est pas fausse, c'est l'explication/justification qui est erronée. Ce que vous constatez, c'est des choses que je fais moi-même, car je suis une personne qui a acquit des réflexes du C et qui les poursuit en C++, et que beaucoup de "vieux" développeurs font, mais c'est des habitudes qu'il n'est pas forcement bon de suivre : les personnes d'une équipe n'ont pas le même background et cela peut déclencher des modes de penser sous-optimales, exactement comme l'à fait le PO.

                        • Partager sur Facebook
                        • Partager sur Twitter
                        Je recherche un CDI/CDD/mission freelance comme Architecte Logiciel/ Expert Technique sur technologies Microsoft.
                          5 juin 2020 à 19:27:30

                          Oui, ce débat est stérile ! J'ai ma vision des structures et des classes pour l'instant, et s'il faut que je m'adapte à un mode de pensée car je mien est obsolète ou pas "dans la norme" je le ferai. D'après ce que tu dis cette façon de différencier les structures et les classes est vieillissante car basée sur le C. Je vais me pencher un peu plus sur le sujet et si vraiment je vois que c'est une mauvais "habitude" alors je m'adapterai.
                          • Partager sur Facebook
                          • Partager sur Twitter
                            5 juin 2020 à 21:54:33

                            Salut,

                            Daimyo_ a écrit:

                            > Ne confondez pas les structures du C et les structures du C++. Une structure C++ EST une classe !!!

                            D'un point de vue syntaxique, oui les classes sont très similaires aux structures, la seule petite différence c'est la portée des membres "par défaut": une classe possède par défaut une portée privée, et une structure possède par défaut une portée publique.

                            Sur ce point, il n'y a rien à dire: il y a bien une différence de portée utilisée par défaut entre une classe et une structure en C++, mais,  cela s'arrête là ;)

                            Daimyo_ a écrit:

                            Sauf qu'une grande partie des programmeurs C++ distinguent ces deux structures de données de façon concrète: Les structure servent exclusivement comme structure de données, et seulement de données et les classes servent de structures de données et d'opérations qui ont un impact sur l'état de ces données (sauf si conception particulière).

                            Même pas...

                            Ou, du moins, pour être plus proche de la réalité, plus depuis au moins vingt ans.

                            A l'heure actuelle, le choix entre le mot clé struct et le mot clé class va essentiellement dépendre de différents facteurs, tels que:

                            • les préférences personnelles du développeur dont
                              • la conformance à certaines règles imposées par certains langages qui font une distinction plus nette entre les deux (comme C#)
                              • la portée que l'on veut voir appliquée au(x) premier(s) élément(s) de la classe (ou de la structure) avant de devoir indiquer une portée différente
                            • parfois la sémantique de la classe (ou de la structure) que l'on souhaite définir, en privilégiant la structure pour la sémantique de valeur et la classe pour la sémantique de valeur
                            • d'autres critères plus ou moins "arbitraires" de la part du développeur

                            rom15 a écrit:

                            Mais on est d'accord que la portée d'une classe est par défaut privée alors que pour une structure c'est publique ?

                            Oui, nous sommes bien d'accord avec cette phrase bien particulière.  La suite de ton développement est un peu plus criticable, parce que

                            rom15 a écrit:

                             Si je veux accéder aux attributs d'une classe il faut utiliser un accesseur, etc... Tout ce principe d'encapsulation,

                            Non, parce que ca, ce n'est pas le principe d'encapsulation...

                            Ou, du moins, ce que tu décris correspond à une vision largement erronée de ce qu'est réellement le principe d'encapsulation.

                            En effet, nombreux sont ceux qui croient que, en plaçant les données en accessibilité privée et en fournissant un accesseur (qui peut avoir du sens, mais qui n'en a pas forcément) et un mutateur (qui n'a jamais de sens), on respecte le principe d'encapsulation.

                            CE N'EST PAS LE CAS!!!

                            Le principe d'encapsulation, il est décrit par ce que l'on appelle la loi de Déméter qui nous dit que

                            Si un objet a de type A manipule en interne un objet b de type B, l'utilisateur de a ne doit pas connaitre le type B pour pouvoir manipuler a

                            Autrement dit, toutes les manipulations que le type A peut entreprendre sur l'objet de type B doivent être exécutées exclusivement par des fonctions qui permettent la manipulation du type A, et que l'utilisateur du type A n'a même pas à savoir (bien qu'il puisse s'en douter) que c'est, au final, un objet de type B qui est manipulé et modifié (ni, d'ailleurs, quelles modifications y sont réellement apportées)

                            Note au passage que je parle de "fonction qui permettent la manipulation du type A" pour n'imposer aucune restriction quant à ce que l'on peut envisager: ce peut tout aussi bien être des fonctions membres de la classe A que des fonctions libres prenant un élément de type a comme paramètre.

                            La structure FILE en C est un parfait exemple d'encapsulation car en tant qu'utiliisateur

                            • on n'a absolument aucune idée des données (et a fortiori du type de celles-ci) que cette structure manipule
                            • on ne connait que quelque fonctions nous permettant de manipuler cette strcture (telles que fopen, fread, fwrite, fclose et autres)

                            Et surtout -- ne le répète à personne -- mais, si on t'assomme avec tous ces principes de conception, c'est parce que leur compréhension et leur mise en oeuvre correctes te permettront d'obtenir plus facilement un programme qui fait ce que tu attends de sa part, qui contient globalement moins de bugs et qui est globalement plus maintenable et plus facile à faire évoluer.

                            Cependant, tu es "une grande personne" et tu restes parfaitement libre de tes propres choix, si bien que, si tu décides de déroger à ces principes, nous te les répéterons ... par principe, tout en acceptant n'importe quelle justification valable (*) que tu pourrais nous donner pour y avoir dérogé.

                            (*) bon, il faudra nous convaincre que cette justification est valable, et surtout qu'elle tienne face à notre contre argumentation.  Mais c'est possible :D

                            rom15 a écrit:

                            Pour moi une classe c'est un truc puissant qui combine des attributs, des méthodes réalisant des opérations.

                            Ben non...

                            Une classe (tout comme une structure, d'ailleurs) n'est que la représentation sous forme de code d'une notion (généralement un nom ou un groupe nominal) qui apparait dans l'analyse des besoins.

                            Cette notion nécessite (généralement)

                            • de pouvoir l'interroger sur son état actuel (peut-être au travers d'accesseur, mais peut être aussi au travers de fonctions qui feront des calculs avant de renvoyer un résultat
                            • de lui donner des ordres (qui auront, le plus souvent, comme résultat de modifier l'état de certaines données)

                            Les données que cette notion manipule en interne, l'utilisateur de la classe (ou de la structure) n'en a rien à foutre: ce qui lui importe, c'est le résultat observé à l'appel des différentes fonctions mises à sa disposition pour manipuler la notion fournie.

                            Dis toi que tu n'es le développeur d'une fonctionnalité (d'une classe ou d'une structure et des fonctions qui permettent de la manipuler) que ... le temps d'écrire le code qui permet la représentation et la manipulation de la notion souhaitée. 

                            Une fois que ce code est écrit (et, à moins que tu ne doive le modifier, bien sur), tu deviens ... un utilisateur "parmi tant d'autres" de la fonctionnalité fournie, et, à ce titre -- c'est peut être l'enseignement le plus dur à accepter -- tu es soumis exactement aux même limitations que n'importe quel autre utilisateur, et donc que le terme "d'imbécile distrait n'attendant que l'occasion de faire une connerie" pour décrire la particularité majeur de tout utilisateur s'applique à toi aussi ;)

                            rom15 a écrit:

                            Qui peut le plus peut le moins, oui on peut faire avec une classe ce que je fait avec les structures, mais personnellement je vois pas l'utilité d'utiliser une classe (ce qui m'obligerait à faire de l'encapsulation) alors que je n'ai aucune méthode à implémenter dedans.

                            Pourquoi serais tu obligé de faire de l'encapsulation?

                            Si tu peux justifier le fait d'avoir laissé une donnée publique et que cette justification tient la route (ne serait-ce que parce que "ben, ici, je n'ai affaire qu'à un ensemble de données qui doivent être utilisées ensembles, mais c'est à l'utilisateur de choisir comment les manipuler"), ben, qu'est ce qui pourrait t'obliger à encapsuler tes données?  Surtout si cette "obligation" t'amène à faire quelque chose qui ne correspond en rien à la notion réelle d'encapsulation ;)

                            • Partager sur Facebook
                            • Partager sur Twitter
                            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
                              8 juin 2020 à 11:49:12

                              @koala01 : Merci pour cette explication de l'encapsulation, quand j'avais suivi le cours C++ d'Open Class Room (à l'époque le site s'appelait Site du Zéro pour vous dire à quel point c'est loin...), j'avais compris que l'encapsulation ça consistait à mettre tous les attributs en private et que c'était absolument satanique de les mettre en public.

                              Bon du coup vous m'avez motivé, je vais refaire tout mon code en mode POO. Simple question en passant : est-ce qu'il est possible pour une classe d'avoir un fichier .h et deux fichiers .cpp ? Je veux regrouper toutes mes fonctions dans une classe et mettre mes paramètres en attributs, mais je préférerai quand même que mes fonctions "routines" et "équations issues de Mathematica" restent séparées dans deux fichiers .cpp différents car les dernières sont des lignes imbuvables d'équations qui font quelques milliers de lignes de code (copié-collé de Mathematica) tandis ce que mes routines sont des méthodes écrites par moi, toutes belles, toutes propres :-°

                              • Partager sur Facebook
                              • Partager sur Twitter
                                8 juin 2020 à 12:17:41

                                Les deux notions de base sont la notion d'invariants et celle de service.

                                Les services c'est ce que tu veux pouvoir faire en utilisant la classe que tu crées. Par exemple, avec une classe Queue, ce que tu veux c'est rajouter un élément, retirer le premier élément, savoir si la file est vide, peut-être savoir sa taille. Tu auras donc des méthodes pour ça. Peut-être que ta file est gérée avec deux piles, peut-être avec un tableau, mais on s'en fout, l'utilisateur veut juste savoir que les services sont remplis (ainsi, l"utilisateur n'a pas à avoir accès à ces deux piles ou à ce tableau).

                                Mais si par exemple un des services attendus est de pouvoir modifier la valeur de quelque chose qui est en attribut, c'est un des services attendus, donc on le laisse en public. S'il y a de la validation à faire, par exemple cette valeur ne peut être qu'entre 0 et 10, on pourrait le mettre en privé et créer une méthode qui rend le service de modifier valeur et de vérifier qu'elle est correcte.

                                Ce point nous permet d'arriver à la notion d'invariant. Les invariants de ton objet, c'est en gros les propriétés qui doivent être respectées à tout moment dans la vie de l'objet. Par exemple, si ta classe Queue a un attribut size, il doit être supérieur ou égal à 0 et ce tout le temps. Si à un moment, il devient inférieur à 0, l'objet atteint un état incorrect. Ainsi, on fait en sorte que cet invariant soit préservé => on fournit de bons services, on fait de bonnes méthodes, etc.

                                Finalement, l'objet doit rendre les services attendus et préserver les invariants.

                                L'idée de service influence également les noms qu'on donne à nos méthodes. Si par exemple on met des serviettes au sale quand elles ont atteint un niveau de saleté, ce qu'on veut c'est savoir si une serviette est propre/sale. Donc on a un is_dirty. Peut-être que c'est géré avec une variable pour le niveau de saleté, peut-être que c'est un compteur de nombre d'utilisations restants, mais ce n'est pas notre affaire. L'utilisateur n'a pas à avoir accès à ces variables. De plus, ça permet de pouvoir passer d'un modèle à l'autre (on décide que finalement avoir un niveau de saleté c'est nul et qu'on préfère avoir un nombre d'utilisations) sans casser l'interface des serviettes (l'utilisateur n'a pas à changer son code vu qu'il utilisait juste is_dirty).

                                -
                                Edité par yo@n97one 8 juin 2020 à 12:17:57

                                • Partager sur Facebook
                                • Partager sur Twitter
                                Tutoriel Ruby - Bon tutoriel C - Tutoriel SDL 2 - Python avancé - Faîtes un zeste, devenez des zesteurs
                                  8 juin 2020 à 12:45:15

                                  >est-ce qu'il est possible pour une classe d'avoir un fichier .h et deux fichiers .cpp ?

                                  Oui, et je te le conseille. (même si des programmes d'aide puissent potentiellement partir en couille)

                                  Mais il est aussi possible de ne pas mettre ce code générer dans une classe, non ?

                                  Il est courant de mettre dans le noms des fichiers contenant du code généré un "_generated_" ou autre pour que le programmeur sache que c'est pas du code "humain" et qu'il ne doit pas le modifier mais plutôt utiliser les outils qui ont généré ce code.

                                  • Partager sur Facebook
                                  • Partager sur Twitter
                                  Je recherche un CDI/CDD/mission freelance comme Architecte Logiciel/ Expert Technique sur technologies Microsoft.
                                    8 juin 2020 à 12:51:17

                                    bacelar a écrit:

                                    >est-ce qu'il est possible pour une classe d'avoir un fichier .h et deux fichiers .cpp ?

                                    Oui, et je te le conseille. (même si des programmes d'aide puissent potentiellement partir en couille)

                                    Mais il est aussi possible de ne pas mettre ce code générer dans une classe, non ?

                                    Il est courant de mettre dans le noms des fichiers contenant du code généré un "_generated_" ou autre pour que le programmeur sache que c'est pas du code "humain" et qu'il ne doit pas le modifier mais plutôt utiliser les outils qui ont généré ce code.


                                    A la base oui je voulais pas le mettre mais sauf que c'est justement ces fonctions dégueulasses qui ont besoin des paramètres de la théorie que je définit maintenant en attribut de ma classe. Du coup le côté pratique pour moi c'est que toutes les méthodes de la classe ont accès à ces paramètres.
                                    • Partager sur Facebook
                                    • Partager sur Twitter
                                      8 juin 2020 à 13:04:21

                                      rom15 a écrit:

                                      Bon du coup vous m'avez motivé, je vais refaire tout mon code en mode POO.

                                      Attention, ce n'est pas parce que l'on utilise le mot clé class que l'on fait forcément de la POO.  Et, d'ailleurs, ce n'est pas parce que l'on utilise le mot clé struct que l'on n'en fait pas; du moins, en C++

                                      Comme on l'a déjà expliqué, il n'y a absolument aucune différence -- hormis la visibilité appliquée par défaut -- entre le mot clé struct et le mot clé class (du moins, en c++).

                                      L'utilisation de fonctions membre, et l'encapsulation que celles-ci permettent -- sauf que, en fait, les fonction libres permettent aussi l'encapsulation -- n'a en définitive rien à voir avec la notion de programmation orientée objets!

                                      Ce qui va faire que l'on utilise le paradigme orienté objets, c'est le fait que l'on décide d'appliquer la seule notion qui n'existe dans aucun autre paradigme. J'ai nommé: la substituabilité.

                                      Autrement dit, ce qui fait que l'on utilise la POO, c'est le fait de pouvoir transmettre un objet de type B comme paramètre à une fonction qui nécessite un paramètre de type A, tout en obtenant un résultat correcte et cohérent.

                                      Quand on fait de la POO, on peut en effet transmettre une Voiture, une Moto ou un Camion à une fonction qui a besoin d'un VehiculeAMoteur pour fournir le résultat attendu parce que Voiture, Camion et Moto sont effectivement des véhicules à moteurs.

                                      En d'autres termes, ce qui fait que l'on utilise la POO, c'est que l'on utilise l'héritage et le polymorphisme.

                                      Il faut juste ne pas oublier que, pour pouvoir utiliser l'héritage, il faut impérativement respecter le LSP (Liskov Substitution Principle ou, si tu préfère en francais, le Principe de Substitution de Liskov)

                                      • Partager sur Facebook
                                      • Partager sur Twitter
                                      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
                                        8 juin 2020 à 14:12:11

                                        > Attention, ce n'est pas parce que l'on utilise le mot clé class que l'on fait forcément de la POO.  Et, d'ailleurs, ce n'est pas parce que l'on utilise le mot clé struct que l'on n'en fait pas; du moins, en C++.

                                        Oui bien sûr, je faisais là un abus de langage sans m'en rendre compte. Je vais juste utiliser une classe pour mon code c'est tout ce que je voulais dire :honte:

                                        • Partager sur Facebook
                                        • Partager sur Twitter
                                          8 juin 2020 à 14:41:40

                                          >> Quand je parle de "paramètres" c'est du point de vue de la théorie physique que j'étudie, pas de l'informatique. Le mot correct du point de vue de mon programme est effectivement "constante" car elle est fixée pendant toute l'exécution.

                                          Il faut savoir ce que tu veux:
                                          - Recompiler chaque fois qu'un paramètre change ou pas ?

                                          Dans le second cas (le plus facile), si tu as la garantie que les "paramètres" ne changent jamais, oui l'utilisation de constantes est viable.
                                          Dans le premier cas  …. ben non, il faut mettre une autre mécanique en place, et le seul moyen en programmation d'introduire la notion de valeur changeante (des valeurs qui peuvent changer au cours de l'execution, ou qui peuvent changer entre deux exécutions) est de passer par des variables. Qu'elles soient native (int, float, char ect …) ou structurées (struct / class), il t'appartient, en tant que programmeur (débutant ou non) de choisir ces dernières pour les intégrer à ton design.

                                          Et toujours coté programmation, le seul moyen propre de donner des valeurs changeantes à une fonctionnalité, est d'utiliser le passage de paramètres.

                                          • Partager sur Facebook
                                          • Partager sur Twitter
                                            8 juin 2020 à 16:17:42

                                            @Deedolith, un peu trop péremptoire, surtout avec un truc aussi vague que "variable" (une expression constexpr et une case mémoire mappée sur un périphérique de compteur Geiger, c'est des "variables" mais cela n'a rien à voir.).

                                            Les codes générés sont souvent conçu pour s'adapter à bon nombre de manière de travailler.

                                            Ou il sont fait à la serpe et c'est au développeur utilisateur de ruser.

                                            Dans les 2 cas, il faut quand même prendre la peine d'essayer de comprendre la logique d'utilisation du machin (cf. lire la documentation).

                                            Si le code généré n'est composé que de fonction libre, ça va être compliqué d'en faire une API utilisable facilement sous forme de classe.

                                            Une manière assez simple de faire avec des paramétrages de simulation, c'est de faire de ces paramètres des champs d'instance d'une classe et le code qui a besoin de ces valeur sera converti en fonction d'instance pour avoir accès directement à ces champs.

                                            Il existe d'autres astuces, mais c'est fonction de comment est architecturé le code généré.

                                            • Partager sur Facebook
                                            • Partager sur Twitter
                                            Je recherche un CDI/CDD/mission freelance comme Architecte Logiciel/ Expert Technique sur technologies Microsoft.

                                            Définir des paramètres à l'éxecution du programme

                                            × 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.
                                            • Editeur
                                            • Markdown