Partage
  • Partager sur Facebook
  • Partager sur Twitter

Class et pointeur

Class et pointeur

Sujet résolu
    14 septembre 2017 à 16:05:31

    Bonjour,

    J'essaye de jouer avec deux class, en essayant de les assembler ensemble, seulement je n'y arrive pas, je ne sais pas comment my prendre. C'est quoi l'utiliter de mettre un attribut sous forme de pointeur? Je comprends pas vraiment, si quelqu'un pouvais m'éclairer la dessus ça serait génial:

    Voici ce que j'ai écrit pour le moment:

    #include <iostream>
    #include <string>
    
    class CreditCard{
    private:
        std::string m_secretCode;
        std::string m_expirationDate;
        std::string m_Name;
        std::string m_Surname;
    public:
        CreditCard() : m_secretCode("0000"), m_expirationDate("31122050"),
                        m_Name("Dupond"), m_Surname("Antoine")
                        {}
        CreditCard(std::string secretCode, std::string expirationDate, std::string name, std::string surname)
        : m_secretCode(secretCode), m_expirationDate(expirationDate),
                        m_Name(name), m_Surname(surname)
                        {}
    
        std::string getName(){
            return m_Name;
        }
    
        std::string getSurname(){
            return m_Surname;
        }
    };
    
    class Distributeur{
    private:
        CreditCard m_userCard; // Pointeur ou pas pointeur ici?
    public:
        Distributeur(const CreditCard &userCard){ // Que faut-il ecrit ici? Je suis obligé d'avoir des "setteur" dans ma class CreditCard?
    
        }
    
        void displayUser(){
    
        }
    };
    
    int main()
    {
        CreditCard a;
        Distributeur distri(a);
    
        distri.displayUser();
    
        return 0;
    }
    


    Je vous remercie d'avance, c'est pas super clair les pointeur et les class pour moi.

    Merci!

    Edit :

    class Distributeur{
    private:
        CreditCard *m_userCard; // Pointeur ou pas pointeur ici?
    public:
        Distributeur(const CreditCard &userCard){ // Que faut-il ecrit ici? Je suis obligé d'avoir des "setteur" dans ma class CreditCard?
        }
    
        void displayUser(){
            std::cout << m_userCard->getName() << std::endl;
        }
    };
    
    int main()
    {
        CreditCard a("1234", "12062018", "Jean", "Claude");
        Distributeur distri(a);
    
        distri.displayUser();
    
        return 0;
    }

    Lorsque je fais ceci, la console m'affiche

    "Segmentation fault" même aprés avoir ajouter un destructeur

     ~Distributeur(){
            delete m_userCard;
        }




    -
    Edité par 238 14 septembre 2017 à 16:20:02

    • Partager sur Facebook
    • Partager sur Twitter
      14 septembre 2017 à 16:23:40

      >C'est quoi l'utiliter de mettre un attribut sous forme de pointeur?

      C'est plutôt l’inconvénient du pointeur que l'utilité, c'est qu'il peut être initialisé à "rien", ce que ne peut pas faire une référence.

      Utilisez des pointeurs intelligents et pas des pointeurs nus pour avoir une gestion de "l'ownership" de l'objet pointé claire et simple.

      Dans MA modélisation d'un "Dirstributeur", il n'y pas forcement de carte de crédit à l'intérieur, donc un pointeur.

      Mais comme la carte de crédit, si elle est dans le distributeur, elle peut pas être ailleurs, c'est un "std::unique_ptr<CreditCard>" qui serait le type du champ.

      CreditCard est une classe Entité (non clonable), il faudra supprimer le constructeur par copie (pour la forme ici) et l'opérateur d'affectation, c'est l'application de la règles des 5.

      http://en.cppreference.com/w/cpp/language/rule_of_three

      P.S.: Utilisez les valeurs par défauts des paramètres plutôt que de multiplier les constructeurs.

      • Partager sur Facebook
      • Partager sur Twitter
      Je recherche un CDI/CDD/mission freelance comme Architecte Logiciel/ Expert Technique sur technologies Microsoft.
        14 septembre 2017 à 16:25:56

        Moi je me demande si on a besoin de polymorphisme pour la carte. Après tout une carte de crédit c'est une carte de crédit. Il n'y a pas grand chose qui change. Et dans ce cas nous pourrions utiliser un std::optional (ou boost::optional si on a pas encore accès au C++17) pour stocker la carte en objet simple.

        • Partager sur Facebook
        • Partager sur Twitter

        git is great because Linus did it, mercurial is better because he didn't.

          14 septembre 2017 à 16:35:45

          >"Segmentation fault" même aprés avoir ajouter un destructeur

          Vous libérez un truc que vous n'avez jamais alloué (avec un new) et qui pointe vers n'importe quoi (pointeur non initialisé).

          Vous prenez pas la tête avec les "new" et les "delete" => pointeurs intelligents ou std::optional.

          • Partager sur Facebook
          • Partager sur Twitter
          Je recherche un CDI/CDD/mission freelance comme Architecte Logiciel/ Expert Technique sur technologies Microsoft.
            14 septembre 2017 à 16:39:50

            markand a écrit:

            Moi je me demande si on a besoin de polymorphisme pour la carte. Après tout une carte de crédit c'est une carte de crédit. Il n'y a pas grand chose qui change. Et dans ce cas nous pourrions utiliser un std::optional (ou boost::optional si on a pas encore accès au C++17) pour stocker la carte en objet simple.


            Je fais surtout ça histoire de m'entrainer avec les classes en paramétres et les pointeurs! J'irais jetais un coup d'oeil une fois que j'aurais réussi mon exercice avant, je te remercie!

            bacelar: Si ça dérange pas, j'aimerais travailler avec les pointeurs classiques dans l'unique but d'apprendre le fonctionnement, bien entendu à l'avenir je me tournerais vers les pointeurs intelligents. Je ne cherche pas la méthode la plus adéquate ici, mais je cherche du code "classique" qui me permettrais éventuellement de comprendre le fonctionnement global.

            J'ai cependant fais une modif par rapport à la copie de Credit Card.

            CreditCard(const CreditCard&) = delete;
            CreditCard &operator=(const CreditCard&) = delete;


            Edit : J'ai pensé à passer ma classe en friend pour plus de facilités mais je sais que c'est une mauvaise idée. Je ne sais pas comment my prendre pour avoir accés aux données de ma Carte via mon Distributeur. Si vous pouviez me donner un exemple de code avec des explications cela serais génial. Merci!

            -
            Edité par 238 14 septembre 2017 à 16:43:32

            • Partager sur Facebook
            • Partager sur Twitter
              14 septembre 2017 à 17:03:54

              Artanno62 a écrit:

              (1) bacelar: Si ça dérange pas, j'aimerais travailler avec les pointeurs classiques dans l'unique but d'apprendre le fonctionnement, bien entendu à l'avenir je me tournerais vers les pointeurs intelligents. Je ne cherche pas la méthode la plus adéquate ici, mais je cherche du code (2) "classique" qui me permettrais éventuellement de comprendre le fonctionnement global.

              J'ai cependant fais une modif par rapport à la copie de Credit Card.

              CreditCard(const CreditCard&) = delete;
              CreditCard &operator=(const CreditCard&) = delete;


              (3) Edit : J'ai pensé à passer ma classe en friend pour plus de facilités mais je sais que c'est une mauvaise idée. Je ne sais pas comment my prendre pour avoir accés aux données de ma Carte via mon Distributeur. Si vous pouviez me donner un exemple de code avec des explications cela serais génial. Merci!

              (1) Je te conseille plutot de commencer par les pointeurs intelligents, les pointeurs nu posent toute une serie de problèmes sur lesquels il est inutile de te focaliser.

              (2) Ce qui etait "classique" hier est obsolête aujourd'hui.
              Fais toi une fleur, et apprend avec les normes actuelles, tu auras bien le temps de te pencher sur celles du passé plus tard.

              (3) Si c'est pour une pure raison de facilité, definir une relation d'amitié entre des classes est une mauvaise idée.
              Cela peut dénoter qu'une classe ne rend pas tous les services que l'on est en droit d'attendre d'elle.

              • Partager sur Facebook
              • Partager sur Twitter
                14 septembre 2017 à 17:05:18

                Note : std::optional et pointeur nu pour ressource optionnelle ne sont pas interchangeables. Optional crée sa propre copie de l'objet. Donc si on veut une ressource distante optionnelle, c'est bien vers un pointeur nu qu'il faut se tourner.

                @Artanno62 : le distributeur est-il responsable de la carte associée dans ton idée ?

                (Reste que new/delete ne vont pas te permettre de piger quoi que ce soit de plus que les pointeurs intelligents, par contre tu vas écrire du code (invisiblement)  faux, ce qui est une mauvaise habitude).

                -
                Edité par Ksass`Peuk 14 septembre 2017 à 17:07:26

                • Partager sur Facebook
                • Partager sur Twitter

                Posez vos questions ou discutez informatique, sur le Discord NaN | Tuto : Preuve de programmes C

                  14 septembre 2017 à 17:25:59

                  Voila je l'ai est donc utilisés comme demandé:

                  #include <iostream>
                  #include <string>
                  
                  class CreditCard{
                  private:
                      std::string m_secretCode;
                      std::string m_expirationDate;
                      std::string m_Name;
                      std::string m_Surname;
                  public:
                      CreditCard() : m_secretCode("0000"), m_expirationDate("31122050"),
                                      m_Name("Dupond"), m_Surname("Antoine")
                                      {}
                      CreditCard(std::string secretCode, std::string expirationDate, std::string name, std::string surname)
                      : m_secretCode(secretCode), m_expirationDate(expirationDate),
                                      m_Name(name), m_Surname(surname)
                                      {}
                  
                      CreditCard(const CreditCard&) = delete;
                      CreditCard &operator=(const CreditCard&) = delete;
                  
                      std::string getName(){
                          return m_Name;
                      }
                  
                      std::string getSurname(){
                          return m_Surname;
                      }
                  };
                  
                  class Distributeur{
                  private:
                      std::unique_ptr<CreditCard> card(new CreditCard());
                  public:
                      Distributeur(const CreditCard &userCard){
                  
                      }
                  
                      void displayUser(){
                          //std::cout << m_userCard->getName() << std::endl;
                      }
                  };
                  
                  int main()
                  {
                      CreditCard a;
                      Distributeur distri(a);
                  
                      distri.displayUser();
                  
                      return 0;
                  }
                  



                  Cependant une erreur est apparue :

                  ""UNique_ptr" in namespace 'std' does not name a template type"

                  Pareil avec:

                  std::unique_ptr<CreditCard> card = std::make_unique<card>();



                  Je comprends pas vraiment, j'ai essayé de retirer le std:: mais rien.

                  (Donc pas besoin de déstructeur avec les pointeurs intelligents si j'ai bien compris?)

                  Mais ma question c'est, j'écris quoi ligne 36 pour copier les attributs de la copie dans mon objet card qui est le pointeur intelligent?

                  Merci

                  -
                  Edité par 238 14 septembre 2017 à 17:32:24

                  • Partager sur Facebook
                  • Partager sur Twitter
                    14 septembre 2017 à 17:35:22

                    Je sais pas si tu as tapé la ligne de l'erreur toi meme ou copier coller mais ..

                    UNique_ptr" in namespace

                    c'est unique_ptr

                    De plus , dans la doc de unique_ptr .. -> Defined in header <tt><memory></tt>

                    -
                    Edité par CrevetteMagique 14 septembre 2017 à 17:36:34

                    • Partager sur Facebook
                    • Partager sur Twitter
                      14 septembre 2017 à 17:37:09

                      Non regarde mon code j'ai juste mal recopier l'erreur

                      ||=== Build: Debug in distributeur (compiler: GNU GCC Compiler) ===|
                      /home/gab/Documents/Programmation/C++/Code::Block/distributeur/main.cpp|33|error: ‘unique_ptr’ in namespace ‘std’ does not name a template type|
                      ||=== Build failed: 1 error(s), 0 warning(s) (0 minute(s), 0 second(s)) ===|
                      


                      Edit : Décidement :p J'ai belle et bien le memory, mais l'erreur est la suivante:

                      ||=== Build: Debug in distributeur (compiler: GNU GCC Compiler) ===|
                      /home/gab/Documents/Programmation/C++/Code::Block/distributeur/main.cpp|34|error: ‘make_unique’ is not a member of ‘std’|
                      /home/gab/Documents/Programmation/C++/Code::Block/distributeur/main.cpp|34|error: expected primary-expression before ‘)’ token|
                      ||=== Build failed: 2 error(s), 0 warning(s) (0 minute(s), 0 second(s)) ===|
                      



                      -
                      Edité par 238 14 septembre 2017 à 17:39:32

                      • Partager sur Facebook
                      • Partager sur Twitter
                        14 septembre 2017 à 17:38:00

                        J'ai editer mon message , il te manque l'include je crois.
                        • Partager sur Facebook
                        • Partager sur Twitter
                          14 septembre 2017 à 17:39:58

                          Je t'ai répondu dans mon edit :)

                          Merci :)

                          • Partager sur Facebook
                          • Partager sur Twitter
                            14 septembre 2017 à 17:43:44

                            as-tu activer c++11/14 ?

                            je crois que make_unique est dispo qu'a partir de ++14.

                            -
                            Edité par CrevetteMagique 14 septembre 2017 à 17:44:01

                            • Partager sur Facebook
                            • Partager sur Twitter
                              14 septembre 2017 à 17:52:40

                              J'ai pas l'option 14 EDIT:

                              -
                              Edité par 238 14 septembre 2017 à 17:54:48

                              • Partager sur Facebook
                              • Partager sur Twitter
                                14 septembre 2017 à 17:57:19

                                Alors ajoute l'option de compilation toi meme ( other compiler options / compiler flags je crois ) il suffi d'ajouter -std=c++14

                                sinon voici l'implementation , tu n'as qu'a ajouter ce code dans ton projet

                                template<typename T, typename... Args>
                                std::unique_ptr<T> make_unique(Args&&... args)
                                {
                                    return std::unique_ptr<T>(new T(std::forward<Args>(args)...));
                                }



                                -
                                Edité par CrevetteMagique 14 septembre 2017 à 17:59:01

                                • Partager sur Facebook
                                • Partager sur Twitter
                                  14 septembre 2017 à 18:03:57

                                  Cela ne change rien, je l'ai ajouté aprés la commande, c'est bien de ça que tu parlais? Fais pas attention à l'erreur, j'ai bien mi 14 :p

                                  Erreur :

                                  ||=== Build: Debug in distributeur (compiler: GNU GCC Compiler) ===|
                                  /home/gab/Documents/Programmation/C++/Code::Block/distributeur/main.cpp|40|error: ‘make_unique’ is not a member of ‘std’|
                                  /home/gab/Documents/Programmation/C++/Code::Block/distributeur/main.cpp|40|note: suggested alternative:|
                                  /home/gab/Documents/Programmation/C++/Code::Block/distributeur/main.cpp|6|note:   ‘make_unique’|
                                  /home/gab/Documents/Programmation/C++/Code::Block/distributeur/main.cpp|40|error: expected primary-expression before ‘)’ token|
                                  ||=== Build failed: 2 error(s), 0 warning(s) (0 minute(s), 0 second(s)) ===|
                                  

                                  Même avec ton implémentation :/

                                  -
                                  Edité par 238 14 septembre 2017 à 18:06:30

                                  • Partager sur Facebook
                                  • Partager sur Twitter
                                    14 septembre 2017 à 19:20:35

                                    /home/gab/Documents/Programmation/C++/Code::Block/distributeur/main.cpp|40|note: suggested alternative:|
                                    /home/gab/Documents/Programmation/C++/Code::Block/distributeur/main.cpp|6|note:   ‘make_unique’|

                                    il a trouvé l'implementation mais tu doit enlever les std

                                    et puis dans ton image, change le 11 pour 14 ? ca ne fonctionne pas ?

                                    -
                                    Edité par CrevetteMagique 14 septembre 2017 à 19:21:03

                                    • Partager sur Facebook
                                    • Partager sur Twitter
                                      14 septembre 2017 à 19:38:09

                                      Merci pour ton aide! Mais malheureusement même résultat, une erreur avec les std retirés et le 14 au lieu du 11

                                      ||=== Build: Debug in distributeur (compiler: GNU GCC Compiler) ===|
                                      /home/gab/Documents/Programmation/C++/Code::Block/distributeur/main.cpp|34|error: ‘unique_ptr’ does not name a type|
                                      ||=== Build failed: 1 error(s), 0 warning(s) (0 minute(s), 0 second(s)) ===|
                                      



                                      • Partager sur Facebook
                                      • Partager sur Twitter
                                        14 septembre 2017 à 19:49:35

                                        faut mettre std:: devant les unique_ptr que tu instanciera , faut juste enlever les std devant l'implementation je t'ai donné ( pour qu'elle t'appartienne , elle n'est pas dans le namespace std )

                                        montre ton code stp

                                        -
                                        Edité par CrevetteMagique 14 septembre 2017 à 19:49:45

                                        • Partager sur Facebook
                                        • Partager sur Twitter
                                          14 septembre 2017 à 19:53:21

                                          Toujours rien

                                          #include <iostream>
                                          #include <string>
                                          #include <memory>
                                          
                                          template<typename T, typename... Args>
                                          std::unique_ptr<T> make_unique(Args&&... args)
                                          {
                                              return std::unique_ptr<T>(new T(std::forward<Args>(args)...));
                                          }
                                          
                                          class CreditCard{
                                          private:
                                              std::string m_secretCode;
                                              std::string m_expirationDate;
                                              std::string m_Name;
                                              std::string m_Surname;
                                          public:
                                              CreditCard() : m_secretCode("0000"), m_expirationDate("31122050"),
                                                              m_Name("Dupond"), m_Surname("Antoine")
                                                              {}
                                              CreditCard(std::string secretCode, std::string expirationDate, std::string name, std::string surname)
                                              : m_secretCode(secretCode), m_expirationDate(expirationDate),
                                                              m_Name(name), m_Surname(surname)
                                                              {}
                                          
                                              CreditCard(const CreditCard&) = delete;
                                              CreditCard &operator=(const CreditCard&) = delete;
                                          
                                              std::string getName(){
                                                  return m_Name;
                                              }
                                          
                                              std::string getSurname(){
                                                  return m_Surname;
                                              }
                                          };
                                          
                                          class Distributeur{
                                          private:
                                              unique_ptr<CreditCard> card = make_unique<card>();
                                          public:
                                              Distributeur(const CreditCard &userCard){
                                          
                                              }
                                          
                                              void displayUser(){
                                                  //std::cout << m_userCard->getName() << std::endl;
                                              }
                                          };
                                          
                                          int main()
                                          {
                                              CreditCard a;
                                              Distributeur distri(a);
                                          
                                              distri.displayUser();
                                          
                                              return 0;
                                          }
                                          



                                          • Partager sur Facebook
                                          • Partager sur Twitter
                                            14 septembre 2017 à 20:13:07

                                            ligne 40 : tu as oublier le std:: devant unique_ptr

                                            ca devrait marcher apres cette correction

                                            -
                                            Edité par CrevetteMagique 14 septembre 2017 à 20:13:22

                                            • Partager sur Facebook
                                            • Partager sur Twitter
                                              14 septembre 2017 à 20:36:20

                                              Zérotisme a écrit:

                                              ligne 40 : tu as oublier le std:: devant unique_ptr

                                              ca devrait marcher apres cette correction

                                              -
                                              Edité par Zérotisme il y a 21 minutes

                                              Négatif :/

                                              ||=== Build: Debug in distributeur (compiler: GNU GCC Compiler) ===|
                                              /home/gab/Documents/Programmation/C++/Code::Block/distributeur/main.cpp|40|error: no matching function for call to ‘make_unique()’|
                                              /home/gab/Documents/Programmation/C++/Code::Block/distributeur/main.cpp|6|note: candidate: template<class T, class ... Args> std::unique_ptr<T> make_unique(Args&& ...)|
                                              /home/gab/Documents/Programmation/C++/Code::Block/distributeur/main.cpp|6|note:   template argument deduction/substitution failed:|
                                              ||=== Build failed: 1 error(s), 0 warning(s) (0 minute(s), 0 second(s)) ===|
                                              

                                              En tous cas merci beaucoup pour ton aide



                                              • Partager sur Facebook
                                              • Partager sur Twitter
                                                14 septembre 2017 à 20:59:00

                                                unique_ptr<CreditCard> card = make_unique<card>();
                                                

                                                =>>

                                                std::unique_ptr<CreditCard> card = make_unique<CreditCard>();
                                                



                                                • Partager sur Facebook
                                                • Partager sur Twitter
                                                J-1 avant demain
                                                  14 septembre 2017 à 21:01:25

                                                  Salut,

                                                  A vrai dire, je n'ai pas tout lu, mais il me semble que le(s) distributeur(s) et les cartes de crédit ont des existences bien séparées...

                                                  Je m'explique : quand il n'y a pas de client devant un distributeur, il ne cesse pas d'exister: il "reste là" à passer son temps à ... attendre qu'un client vienne lui donner une carte de crédit.

                                                  Il en va de même pour les cartes de crédit : ce n'est pas parce qu'elles ne sont pas dans un distributeur qu'elle cessent d'exister: quand elles ne sont pas dans un distributeur, elles "passent leur temps" dans le portefeuille de leur propriétaire (que l'on espère légitime) à ... attendre d'en être sortie pour aller dans un distributeur.

                                                  De plus, quelle que soit la demande que l'on peut faire à un distributeur, il ne peut connaitre une carte de crédit particulière que... tant que l'utilisateur ne l'a pas réclamée.

                                                  Tout cela pour dire qu'il n'y a -- à mon avis -- aucun sens de créer une variable membre de type CreditCard dans la classe Distributeur.

                                                  Ce qu'il y a, c'est qu'un distributeur a un "accès privilégié" à certaines informations de la carte de crédit.  Principalement, il a accès au code secret qui est sensé être connu uniquement par son propriétaire légitime: il faut non seulement qu'il puisse comparer le code introduit par l'utilisateur avec celui de la carte, mais aussi (si cela fait partie de ses attributions) qu'il puisse le modifier à la demande de l'utilisateur.

                                                  L'idée est donc de faire en sorte que toutes les fonctions qui ont besoin de la carte puisse en disposer sous forme de paramètre, en sachant que la première chose qu'il doit faire, c'est accepter la carte d'un utilisateur et que la dernière chose qu'il doive faire (avant de se remettre en attente), c'est de la lui rendre.

                                                  Du coup, nous devrions sans doute déclarer le distributeur comme étant ami de la carte de crédit, ce qui donnerait à cette dernière une forme proche de

                                                  class CreditCard{
                                                  public:
                                                      CreditCard(std::string const & name, 
                                                                 std::string const & surname,
                                                                 date expiration, unsigned int code)
                                                                 :name_{name}, surname_{surname},
                                                                  expiration_{expiration}, code_{code},
                                                                  tries_{0}{}
                                                      date const & expiration() const{return expiration_;}
                                                      std::string const & userName() const{return name_;}
                                                      std::string const & userSurName() const{return name_;}
                                                      bool blocked() {return tries_=3;}
                                                  private:
                                                      friend class Distributeur;
                                                      void codeAccepted(){tries_=0;}
                                                      void codeRejected(){++ tries_;}
                                                      void changeCode(int newCode){code_ = newCode;}
                                                      unsigned int code() const{return code_;}
                                                      std::string name_;
                                                      std::string surname_;
                                                      date expiration_;
                                                      unsigned int code_;
                                                      unsigned int tries_;
                                                  
                                                  };

                                                  (vous remarquerez que j'ai ajouté une information essentielle : le nombre d'essais au dela duquel la carte sera bloquée)

                                                  Je vous propose maintenant de réfléchir à ce que doit faire un distributeur.  La première chose qu'il doit faire, c'est d'accepter une carte de crédit.  Et c'est le seul service qu'il doit exposer.  Tout le reste ne pourra se faire qu'au travers de ce service unique.

                                                  Mais, en interne, il devra faire pas mal de chose, dont plusieurs avec la carte de crédit, à savoir:

                                                  • saluer le propriétaire de la carte
                                                  • tester sa date de validité: si la carte est invalide, il doit l'avaler (ou la rendre inutilisable)
                                                  • (en plusieurs circonstances) comparer le code donné par l'utilisateur avec celui de la carte et signaler à la carte quand le code est accepté et quand il est refusé.
                                                  • Si le code a été refusé trop souvent sans que le bon code n'ait été introduit (j'ai placé la limite en dur dans la fonction blocked), il doit avaler la carte (ou la rendre inutilisable).
                                                  • si la carte est valide et utilisable, il devra rentrer dans une boucle dans laquelle il laissera le choix à l'utilisateur de ce qu'il veut faire

                                                  Au final, je verrais bien notre classe distributeur prendre une forme proche de

                                                  class Distributeur{
                                                  enum CardState{
                                                      accepted,
                                                      rejected,
                                                      finished,
                                                      waiting
                                                  };
                                                  public:
                                                      void acceptCard(CreditCard & c){
                                                          checkCard(c);
                                                          /* ici, on entre dans une boucle tant que la carte est dans l'état "valide"*/
                                                          if(state_ == accepted){
                                                              do{
                                                                  size_t choix = menu(c);
                                                                  /* on sélectionne ce qu'il faut faire selon le
                                                                   * choix de l'utilisateur
                                                                   */
                                                                  if (choix ==restitution){
                                                                      state_=finished;
                                                                  }
                                                              }while(state_==accepted); 
                                                          }
                                                          if(state_==rejected)
                                                              avalerCarte(c);
                                                          else()
                                                               rendreCarte();
                                                      }
                                                  private:
                                                      void saluserUtilisateur(CreditCard const & c){
                                                          std::cout<< "Bonjour, "<< c.surName()<< " "
                                                                   << c.name()<<"\n";
                                                      }
                                                      size_t menu(CreditCard const & c){
                                                          saluterUtilisateur(c);
                                                          /* afficher tous les choix */
                                                      }
                                                      void rendreCarte(){
                                                          state_=waiting;
                                                      }
                                                      void checkCard(CreditCard const & c){
                                                          if(currentDate_ >= c.expiration() || c.blocked())
                                                              state_= rejected;
                                                          else{
                                                              state_=accepted;
                                                          }
                                                      }
                                                      void avalerCarte(CreditCard & c){
                                                          /* rendre la carte inutilisable, l'avaler, et appeler la police */
                                                          appelerPoliceSansRienDire();
                                                      }
                                                      void askCode(CreditCard & c){
                                                          std::cout<<"Veuillez introduire votre code secret ";
                                                          /* faudra le faire mieux que cela  */
                                                          size_t code;
                                                          std::cin>> code;
                                                          if(code==c.code())
                                                              c.codeAccepted();
                                                          else{
                                                              c.codeRejected();
                                                          }
                                                          checkCard(c);
                                                      }
                                                      /* quelques possibilités parmi d'autres */
                                                      void changerCode(CreditCard & c){
                                                          askCode(c);
                                                          /* ... */
                                                      }
                                                      void afficherSolde(CreditCard & c){
                                                          askCode(c);
                                                          /* ... */
                                                      }
                                                      void retirerArgent(CreditCard & c){
                                                          askCode(c);
                                                          /* ... */
                                                      }
                                                      date currentDate_;
                                                      CardState state_{waiting};
                                                  };

                                                  Comme tu le vois, le distributeur ne connait à chaque fois la carte de crédit que par les paramètres reçus par les différentes fonctions ;)

                                                  -
                                                  Edité par koala01 14 septembre 2017 à 23:01:56

                                                  • 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
                                                    14 septembre 2017 à 22:30:25

                                                    Merci énormement pour l'explication Koala! C'est trés clair et précis et en plus appuyer avec un exemple c'est beaucoup plus compréhensibles.

                                                    Mais il me reste un petit truc que je ne comprends pas vraiment:

                                                    -Comment reprendre ton exemple sans que les deux classes ne soient amies? C'est vraiment l'un des principales objectif que je m'étais donné :) Comment faire en sorte que le distributeur prennent en lui la carte et arrive à lire les attributs de la carte?

                                                    Si on regarde mon code dans mon tout premier post, je bloque complétement au niveau de la ligne 33, je ne sais pas comment prendre les attributs de &userCard pour les mettres dans m_userCard.

                                                    Je vais cependant m'entrainer avec ton code et vois si je maitrise tout cela!

                                                    Merci beaucoup pour avoir pris le temps d'expliquer!

                                                    EDIT :

                                                    Pour le moment j'ai reussi avec mon exemple à faire fonctionner le code mais en utlisant les classes amies:

                                                    #include <iostream>
                                                    #include <string>
                                                    #include <memory>
                                                    
                                                    template<typename T, typename... Args>
                                                    std::unique_ptr<T> make_unique(Args&&... args)
                                                    {
                                                        return std::unique_ptr<T>(new T(std::forward<Args>(args)...));
                                                    }
                                                    
                                                    class CreditCard{
                                                    private:
                                                        std::string m_secretCode;
                                                        std::string m_expirationDate;
                                                        std::string m_Name;
                                                        std::string m_Surname;
                                                        friend class Distributeur;
                                                    
                                                    public:
                                                        CreditCard() : m_secretCode("0000"), m_expirationDate("31122050"),
                                                                        m_Name("Dupond"), m_Surname("Antoine")
                                                                        {}
                                                        CreditCard(std::string secretCode, std::string expirationDate, std::string name, std::string surname)
                                                        : m_secretCode(secretCode), m_expirationDate(expirationDate),
                                                                        m_Name(name), m_Surname(surname)
                                                                        {}
                                                    
                                                        CreditCard(const CreditCard&) = delete;
                                                        CreditCard &operator=(const CreditCard&) = delete;
                                                    
                                                        std::string getName(){
                                                            return m_Name;
                                                        }
                                                    
                                                        std::string getSurname(){
                                                            return m_Surname;
                                                        }
                                                    };
                                                    
                                                    class Distributeur{
                                                    private:
                                                        CreditCard *m_userCard;
                                                    public:
                                                        Distributeur(const CreditCard &userCard){
                                                            m_userCard = new CreditCard;
                                                            m_userCard->m_Name = userCard.m_Name;
                                                        }
                                                    
                                                        ~Distributeur(){
                                                            delete m_userCard;
                                                        }
                                                    
                                                        void displayUser(){
                                                            std::cout << m_userCard->getName() << std::endl;
                                                        }
                                                    };
                                                    
                                                    int main()
                                                    {
                                                        CreditCard a("1234","01062020","Alfred","Bernard");
                                                        Distributeur distri(a);
                                                    
                                                        distri.displayUser();
                                                    
                                                        return 0;
                                                    }
                                                    

                                                    (Désolé mais les pointeurs intelligents ne voulais pas montrer le bout de leur tête :p )

                                                    J'utilise le pointeur justement pour que quand l'utilisateur retire sa carte, il pointe sur 'nullptr'. Bonne idée ou je me prends la tête pour rien?

                                                    Y a t'il une autre façon avec mon code de faire en sorte de supprimer la ligne 17 friend class et de ne pas brisser la loi de l'encapsulation?

                                                    Hésitez pas à commenter mon code! :)

                                                    Merci!

                                                    -
                                                    Edité par 238 14 septembre 2017 à 22:43:58

                                                    • Partager sur Facebook
                                                    • Partager sur Twitter
                                                      14 septembre 2017 à 23:13:22

                                                      Artanno62 a écrit:

                                                      <snip>

                                                      (1)J'utilise le pointeur justement pour que quand l'utilisateur retire sa carte, il pointe sur 'nullptr'. Bonne idée ou je me prends la tête pour rien?

                                                      (2)Y a t'il une autre façon avec mon code de faire en sorte de supprimer la ligne 17 friend class et de ne pas brisser la loi de l'encapsulation?

                                                      (1) tu te prends la tête pour rien dans le cas présent...

                                                      Une donnée membre n'a de sens que si que si une instance de ta classe ne peut pas exister sans elle, et / ou qu'il lui est impossible de disposer de l'information "autrement"

                                                      (2) Parce que tu trouves que je brise l'encapsulation ???  Au contraire, je la renforce!!!

                                                      L'un dans l'autre, tu briserais bien plus l'encapsulation en placant des accesseurs (getXXX) et (surtout) des mutateurs (setXXX) sur chacune des données membres de ta classe.

                                                      Ici, les fonctions membres de CreditCard userName, userSurname et (dans une moindre mesure) blocked sont, effectivement, des accesseurs, mais ils ont le intérêt parce qu'il correspondent  à un service que je suis en droit d'attendre de la part de la carte de crédit.  A savoir: en connaitre le propriétaire et savoir jusqu'à quand elle est valide ;)

                                                      Mais tu remarqueras que je ne donne aucun moyen de modifier ces données ;)

                                                      Dans le cas présent, si je ne déclarais pas la classe Distributeur comme étant amie de la classe CreditCard, j'aurais du exposer les possibilités d'accès et de modification du code à tout le monde.  Et je me serais retrouvé dans la merde, car cela aurait signifié que n'importe qui (y compris le méchant pick pocket qui vient de faire les poches d'un pauvre malheureux)  pouvait aller le récupérer ou, pire encore, pouvait aller le modifier à sa guise.

                                                      Par contre, de la manière dont je m'y suis pris, tu remarqueras que je ne fais qu'appeler des fonctions auxquelles (seule) la classe Distributeur a accès.  Si j'avais voulu imposer certaines restrictions au niveau du code, j'aurais tout aussi bien pu les ajouter à la fonction changerCode ;).

                                                      Allez, un peu de lecture pour te convaincre de ce que je dis ;)

                                                      • 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
                                                        14 septembre 2017 à 23:47:09

                                                        Et bien! Je venais ici pour apprendre à faire communiquer deux classes entre elle et j'en apprends bien plus! Merci beaucoup Koala, je pensais que l'amitié c'etait quelques chose qui venais casser l'encapsulation, mais au final quand c'est bien utilisé, ça la renforce finalement.

                                                        J'ai par contre pas compris ton premier point

                                                        Une donnée membre n'a de sens que si que si une instance de ta classe ne peut pas exister sans elle, et / ou qu'il lui est impossible de disposer de l'information "autrement"

                                                        Je ne suis pas sur d'avoir compris.. ce code est à premiére vue fonctionnel et dans mon main ma classe me rend le service que j'attends d'elle

                                                        class Distributeur{
                                                        private:
                                                            CreditCard *m_userCard;
                                                        public:
                                                            Distributeur(const CreditCard &userCard){
                                                                m_userCard = new CreditCard;
                                                                m_userCard->m_Name = userCard.m_Name;
                                                            }
                                                        
                                                            ~Distributeur(){
                                                                delete m_userCard;
                                                            }
                                                        
                                                            void displayUser(){
                                                                if(m_userCard == 0){
                                                                    std::cout << "Pas de cartes" << std::endl;
                                                                }
                                                                else{
                                                                    std::cout << m_userCard->getName() << std::endl;
                                                                }
                                                            }
                                                        
                                                            void retirerCarte(){
                                                                m_userCard = nullptr;
                                                            }
                                                        
                                                            void insererCarte(const CreditCard &userCard){
                                                                m_userCard = new CreditCard;
                                                                m_userCard->m_Name = userCard.m_Name;
                                                            }
                                                        };
                                                        
                                                        int main()
                                                        {
                                                            CreditCard a("1234","01062020","Alfred","Bernard");
                                                            CreditCard b("9876", "05122048", "Kurt", "Cobain");
                                                            Distributeur distri(a);
                                                        
                                                            distri.displayUser();
                                                        
                                                            distri.retirerCarte();
                                                        
                                                            distri.displayUser();
                                                        
                                                            distri.insererCarte(a);
                                                        
                                                            distri.displayUser();
                                                        
                                                            distri.retirerCarte();
                                                        
                                                            distri.insererCarte(b);
                                                        
                                                            distri.displayUser();
                                                        
                                                            return 0;
                                                        }
                                                        

                                                        J'etais poutant fiers de ça :p




                                                        -
                                                        Edité par 238 14 septembre 2017 à 23:50:14

                                                        • Partager sur Facebook
                                                        • Partager sur Twitter
                                                          15 septembre 2017 à 7:33:49

                                                          Ça fuit de partout ;) .

                                                          Mais mis à part cela, il n'y pas de raison de rendre le distributeur responsable de la durée de vie de la carte qu'il reçoit.

                                                          • Partager sur Facebook
                                                          • Partager sur Twitter

                                                          Posez vos questions ou discutez informatique, sur le Discord NaN | Tuto : Preuve de programmes C

                                                            15 septembre 2017 à 10:24:43

                                                            Artanno62 a écrit:

                                                            Et bien! Je venais ici pour apprendre à faire communiquer deux classes entre elle et j'en apprends bien plus! Merci beaucoup Koala, je pensais que l'amitié c'etait quelques chose qui venais casser l'encapsulation, mais au final quand c'est bien utilisé, ça la renforce finalement.

                                                            J'ai par contre pas compris ton premier point

                                                            Une donnée membre n'a de sens que si que si une instance de ta classe ne peut pas exister sans elle, et / ou qu'il lui est impossible de disposer de l'information "autrement"

                                                            Bon, reprenons depuis le début:

                                                            Tu dois réfléchir à tes classes en tant que "fournisseur de services"; c'est à dire que tu dois commencer par réfléchir aux ordre qu'elles peuvent recevoir (ex: "accepte une carte de crédit", "appeler la police") ou aux questions auxquelles elle devra répondre (ex: "donne moi le nom de l'utilisateur").

                                                            Certains de ces services seront "accessibles à tous" (ex: "donne moi le nom de l'utilisateur", "accepte une carte de crédit"), d'autres seront à "usage interne uniquement" (ex: "appeler la police").  C'est pour cela que tu en mettra certains dans l'accessibilité publique, et d'autres dans l'accessibilité privée (ou protégée).

                                                            Mais, pour pouvoir obéir aux ordres qui lui sont données ou pour pouvoir répondre aux questions qui lui sont posées, une classe va -- forcément -- devoir manipuler des données.

                                                            Certaines de ces données font partie intégrante de la classe, dans le sens où, si la classe n'en dispose pas, elle sera purement et simplement dans l'incapacité de fournir certains services que l'on attend de sa part.  C'est le cas des données représentant le nom ou le prénom du propriétaire de la carte, sa date d'expiration ou le code secret qui y est rattaché.

                                                            Dans ce cas, ces données doivent appartenir à ta classe, et tu en feras des données membres.

                                                            Mais, dans certains cas, les services s'attendent à ce que l'utilisateur de la classe leur fournissent certaines données sans lesquelles ils ne pourront pas travailler correctement:

                                                            Si tu veux que ta classe enregistre une information dans "un fichier quelconque", si tu veux que ton distributeur puisse travailler avec "n'importe quelle carte de crédit existante", il n'y a aucune raison pour que ta classe ne puisse pas exister sans connaître cette information.  Il faut juste veiller à ce qu'elle la connaisse... au moment où elle en auras besoin.  C'est à dire, au moment où l'utilisateur de la classe fera appel à la fonction qui a besoin de cette information pour travailler.

                                                            A ce moment là, c'est à l'utilisateur de la fonction de veiller à fournir "l'information manquante". Comment? en la fournissant sous la forme d'un paramètre.

                                                            Comme je te l'ai dit, ton distributeur ne doit connaître une carte de crédit que... lorsqu'il est occupé à la manipuler.  Il peut très bien continuer à exister (après tout, on ne va pas retirer le distributeur du mur entre deux clients à chaque fois, ca ferait désordre :D ), sans avoir connaissance de la moindre carte de crédit!

                                                            Il n'y a donc aucune raison de créer une donnée membre permettant la représentation d'une carte de crédit dans la classe Distributeur.

                                                            Par contre, de très nombreux services (internes ou externes) rendus par le distributeur ont besoin de la carte de crédit pour travailler.  A commencer par le service qui consiste à ... accepter que le client introduise sa carte.  Mais c'est aussi le cas du service qui va saluer le client, de celui qui va s'occuper de vérifier le code secret et de plein d'autres services encore.

                                                            Toutes les fonctions associées à ces différents services devront donc recevoir ... une carte de crédit de la part de la fonction qui les appelle sous la forme d'une paramètre.

                                                            Est-ce que cela te semble plus clair à présent ?

                                                            • 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
                                                              15 septembre 2017 à 14:03:24

                                                              Je serais curieux de savoir ou ça fuit :p

                                                              Cela me semble beaucoup plus clair en effet :) Le distributeur n'as pas besoin d'une donnée membre carte de crédit pour travailler. C'est vraiment très clair maintenant, je vais essayer de m’entraîner à les refaire en appliquant les conseils donnés. 

                                                              Le plus dur finalement c'est vraiment le fait de venir structurer la classe avant même d'écrire la première ligne de code. Pour moi mettre une donnée membre dans le distributeur ne faisais pas en sorte que le distributeur "mourait" en même temps que la carte lorsqu'elle était retirée.

                                                              En tout cas merci beaucoup d'avoir pris le temps de m'expliquer! :)

                                                              -
                                                              Edité par 238 15 septembre 2017 à 14:05:49

                                                              • Partager sur Facebook
                                                              • Partager sur Twitter

                                                              Class et pointeur

                                                              × 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