Partage
  • Partager sur Facebook
  • Partager sur Twitter

surcharge opérateur d'affectation

    19 février 2018 à 2:17:49

    bonjour,

    je ne vois vraiment pas où est l'erreur

    production::production(production const& prodACopier):m_tete(prodACopier.m_tete){
       for(int i(0);i<prodACopier.m_corpProd.size();i++)
          m_corpProd[i]=new enreg(*(prodACopier.m_corpProd[i]));
    }
    
    production& production::operator=(production const& productionACopier){
       if(this != &productionACopier){
          m_tete=productionACopier.m_tete;
          for(int i(0);i<prodACopier.m_corpProd.size();i++){
             delete m_corpProd[i];
             m_corpProd[i]=new enreg(*(productionACopier.m_corpProd[i]));
          }
       }
       return *this;
    }
    
    class production{
    public:
       production(nonTerm tete,std::vector<enreg*> corpProd);
       production();
       production(production const& prodACopier);
       ~production();
       void affiche(std::ostream &flux) const;
    private:
       nonTerm m_tete;
       std::vector<enreg*> m_corpProd;
    };
    
    $ g++ -c syntaxique.cpp syntaxique.cpp:27:70: error: definition of implicitly-declared ‘production& production::operator=(const production&)’
     production& production::operator=(production const& productionACopier){

    quelqu'un a une idée?

    -
    Edité par MathieuSerpa 19 février 2018 à 2:21:24

    • Partager sur Facebook
    • Partager sur Twitter
      19 février 2018 à 3:51:14

      Tu définis une fonction membre operator=, sans mettre de déclaration dans le prototype de la classe.

      Au passage, ton code serait mille fois plus simple avec des pointeur intelligent comme std::unique_ptr.

      • Partager sur Facebook
      • Partager sur Twitter
        19 février 2018 à 4:27:59

        Salut,

        Bon, déjà, le test d'auto affectation (le if (this != & productionACopier) ) , tu peux le virer, car il ne sert à rien.

        Ensuite, il existe quatre grandes fonctions "de base" si l'on s'en réfère à la forme canonique orthodoxe de Coplien:

        • Le constructeur par défaut
        • le constructeur de copie
        • l'opérateur d'affectation et
        • le destructeur

        Sur ces quatre grandes fonctions, il existe une règle nommée "règle des trois grands" qui dit que si tu définis toi-même l'une des fonctions que sont le constructeur de copie, l'opérateur d'affectation ou le destructeur, alors, tu dois fournir la définition des trois.

        Le truc, c'est que l'opérateur d'affectation et le constructeur de copie sont intimement liés, au point qu'un code proche de Type copy = objetExistant se traduira vraisemblablement par l'appel du constructeur de copie, et non par celui de l'opérateur d'affectation.

        De plus, si l'on veut donner la sémantique d'entité à une classe, on se rend compte que l'on interdit aussi bien la copie que l'affectation ;)

        Enfin, on se rend compte que le code du constructeur de copie se trouve intégralement (à l'exception de la liste d'initialisation, qui n'existe pas pour l'opérateur d'affectation) dans l'opérateur d'affectation.

        Du coup, le plus facile pour s'assurer que tout soit fait "dans l'ordre" (y compris la libération de la mémoire, le cas échéant), on a généralement recours à l'idiome "copy and swap" (copie et échange) pour implémenter l'opérateur d'affectation.

        Le principe est simple et se fait en trois temps:

        • dans un premier temps, on va créer une copie (avec le constructeur de copie) de l'élément que l'on veut assigner à notre donnée
        • dans un deuxième temps, on va intervertir les données membres de la copie que l'on vient de créer avec celles de l'objet courant.
        • dans un troisième temps, on va ... renvoyer l'objet courant

        Par facilité, nous créerons sans doute une fonction membre "swap(Type &)" qui se chargera d'intervertir les données membres d'un élément avec celles de l'élément courant.  Elle prendra une forme proche de

        void Production::swap(Production & other){
            /* std::swap nécessite l'inclusion soit du fichier
             * d'en-tête <algorithm> soit du fichier d'en-tête
             * <utility>
             */
            std::swap(m_tete, other.m_tete);
            std::swap(m_corpProd, other m_corpProd);
        }

        et, grace à cela, ton opérateur d'affectation pourra ressembler à quelque chose "d'aussi simple" que

        Production & operator=(Production const & other){
            /* on crée la copie conforme de other */
            Production copy{other};
            /* on interverti les données membres de la copie
             * et de l'objet courant
             */
            swap(other);
            /* on renvoie l'objet courant */
            return *this;
        } // la copie est automatiquement détruite ici
          // ce qui implique que son destruteur est appelé
          // et donc, a priori, que delete est bien appelé sur les
          // pointeurs contenus par m_corpProd

        NOTA:

        1- Depuis maintenant sept ans, nous disposons dans la bibliothèque standard de pointeurs intelligents, dont std::unique_ptr (avant, on en disposait, mais il fallait utiliser boost)

        Tu devrais vraiment t'intéresser à cette classe, car elle facilite énormément la vie.

        2 a- Je ne sais pas à quoi correspond ton type enreg, dont fournis un plein tableau, mais, a priori, nous sommes sans doute en face d'une hiérarchie de classe avec ce type (et, plus précisément, de la classe de base qui a servi à construire cette hiérarchie).  Si c'est le cas, le type enreg devrait avoir sémantique d'entité, ce qui voudrait dire que l'on ne veut surtout pas pouvoir copier les différentes instances que l'on a mis dans le tableau!!!

        Il me semble donc plus qu'utile de réfléchir à la responsabilité prise par ta classe production: devient-elle le propriétaire légitime des éléments contenus dans le tableau (ce qui implique que celui qui a rempli ce tableau n'en est plus responsable une fois que tu as transmis le tableau à ton instance de production), ou n'en est-elle qu'un "utilisateur parmi d'autres" ???

        Dans tous les cas, il semblerait que ta classe production soit également un candidat idéal à la sémantique d'entité.  Et, dans ce cas, ce n'est pas redéfinir le constructeur de copie et l'opérateur d'affectation que tu dois faire, mais... les interdire, carrément...

        2 b- En plus, si tu es effectivement dans le cadre d'une hiérarchie de classes, le fait de faire appel a new enregistrement(/* ... */ ) a de grandes chances de te faire n'importe quoi, à l'exception de ce que tu souhaites ;)

        3- Si le type enreg n'intervient pas dans une hiérarchie de classes, tu n'as aucune raison d'utiliser un tableau de pointeur.  Mais, dans ce cas, tu peux laisser le compilateur générer son constructeur de copie et son opérateur d'affectation avec son implémentation par défaut, car tout se fera automatiquement ;)

        • 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
          20 février 2018 à 1:57:19

          merci pour vos contributions

          peut-on m'en dire plus sur std::unique_ptr?

          le but de ce code est d'avoir des enregistrement terminaux et non-terminaux (enregT et enregNT, qui dérivent de enreg) dans une collection hétérogène, à l'aide de vector, car je leur applique un traitement différends grâce aux méthodes virtuelles. ces collections sont appelées production.

          le code que je propose fait en sorte que deux pointeurs de types qui dérivent enreg ne pointe pas sur le même objet tout en étant une copie.

          il y aura un tableau qui est la table d'analyse d'un analyseur LL et contient des productions

          pour écrire cette surcharge d'opérateur d'affectation, je me suis inspiré du cours C++ openclassroom, mais j'en suis au polymorphisme. Peut-être que plus loin dans ce cours j'en apprendrais plus sur ces pointeurs intelligent

          sinon, j'ai ajouté la déclaration de l'oprateur= dans la classe production et ça ne me fait plus d'erreurs de compilation

          • Partager sur Facebook
          • Partager sur Twitter
            20 février 2018 à 8:34:07

            MathieuSerpa a écrit:

            peut-on m'en dire plus sur std::unique_ptr?

            C'est un pointeur qui a comme sémantique d'être l'unique propriétaire de la ressource associée, et qui détruit la ressource quand il est lui même détruit. Voir documentation : http://en.cppreference.com/w/cpp/memory/unique_ptr .

            MathieuSerpa a écrit:

            le but de ce code est d'avoir des enregistrement terminaux et non-terminaux (enregT et enregNT, qui dérivent de enreg) dans une collection hétérogène, à l'aide de vector.

            Donc, comme l'a dit @koala01, ta classe à une sémantique d'entité, elle devrait être non-copiable et non assignable par copie.

            MathieuSerpa a écrit:

            le code que je propose fait en sorte que deux pointeurs de types qui dérivent enreg ne pointe pas sur le même objet tout en étant une copie.

            Jette cette copie, elle n'a rien à faire là. Supprime la, elle devrait de toute façon être interdite.

            MathieuSerpa a écrit:

            pour écrire cette surcharge d'opérateur d'affectation, je me suis inspiré du cours C++ openclassroom, mais j'en suis au polymorphisme. Peut-être que plus loin dans ce cours j'en apprendrais plus sur ces pointeurs intelligent

            Ce "cours" est une aberration, quelques recherches sur le forum t'expliqueront les raisons et te redirigeront vers des tutoriels corrects.

            • Partager sur Facebook
            • Partager sur Twitter

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

            surcharge opérateur d'affectation

            × 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