Partage
  • Partager sur Facebook
  • Partager sur Twitter

Le pourquoi du comment on surcharge l'opérateur <<

référence au cours C++ d'OpenClassroom

Sujet résolu
    27 juillet 2020 à 13:23:59

    Bonjour,

    Remise en contexte : ma question pose sur la surcharge de l’opérateur << présentée ici.

    Pour épargner les clics et la relecture, je vais recopier ici ce qui m'interpelle. tout ce qui suit, jusqu'à nouvelle précision, est de la citation. Duree est une classe créée plus tôt dans le chapitre. :

    Implémentation de operator<< :

    ostream& operator<<( ostream &flux, Duree const& duree )
    {
        duree.afficher(flux);
        return flux;
    }

    (Dans le fichier Duree.cpp)
    On crée ensuite une méthode afficher() dans la classe Duree, qui permet peut accéder aux attributs de la durée (m_heures, m_minutes, m_secondes) et les afficher.

    void Duree::afficher(ostream &flux) const
    {
        flux << m_heures << "h" << m_minutes << "m" << m_secondes << "s";
    }

    (dans le fichier Duree.cpp)

    dont le prototype (dans le fichier Duree.h) est :

    void afficher(std::ostream &flux) const;

    (dans la classe bien entendu)

     Grâce à cela, dans le main(), on peut directement faire :

    int main()
    {
        Duree duree1(2, 25, 28), duree2(0, 16, 33);
        
        cout << duree1 << " et " << duree2 << endl;
    
        return 0;
    }

    Fin de citation.

    ma question est : Pourquoi passe-t'on le flux (cout) en paramètre à la méthode Duree::afficher() ?

    Par curiosité, j'ai modifié le code du cours de cette manière :

    Duree.h :

    #ifndef DEF_DUREE
    #define DEF_DUREE
    
    #include <iostream>
    class Duree
    {
    	int a_hours;
    	int a_minutes;
    	int a_seconds;
    
    public:
            /...
    	void show() const;
    };
    
    
    /...
    
    std::ostream &operator<<(std::ostream &flux, Duree const& duree);
    #endif DEF_DUREE

    Duree.cpp :

    #include "Duree.h"
    
    /...
    
    void Duree::show() const
    {
    	cout << a_hours << ":" << a_minutes << "." << a_seconds << endl;
    }
    
    /...
    
    ostream &operator<<(ostream &flux, Duree const& duree)
    {
    	duree.show();
    	return flux;
    }

    et j'obtient exactement le même résultat ! Je me doute que ce n'est pas fait par hasard (comme les #ifndef DEF_DUREE et #define DEF_DUREEau début des headers, que j'ai snobé jusqu'à avoir des erreurs en faisant des combinaisons de classe). Alors j'aimerai savoir précisément, pourquoi on fait comme ça, et pas comme la modification que j'ai proposée ? Dans quelle situation, plus complexe que celle du cours, je risque d'avoir des problèmes à faire à "ma manière" ?

    Merci d'avance pour vos réponses. :)

    • Partager sur Facebook
    • Partager sur Twitter
      27 juillet 2020 à 13:46:10

      PCMRF a écrit:

      ma question est : Pourquoi passe-t'on le flux (cout) en paramètre à la méthode Duree::afficher() ?

      Parce que l'opérateur << ne fonctionne pas seulement qu'avec la sortie standard (std::cout), mais avec tous les types de flux de sorties qui existent, ce qui comprend:

      • le flux de sortie d'erreur (std::cerr)
      • les fichiers (std:: ofstream)
      • les flux de conversion (std::ofstringstream, de moins en moins utilisés)
      • n'importe quel flux de donnée que tu pourrais envisager de développer toi meme

      Cela s'apparente au  respect d'un principe connu sous le nom de DIP (Dependancy Inversion Principle ou principe des inversions de dépendances):

      La fonction afficher de ta durée se fout pas mal de savoir si elle sera envoyée sur la sortie standard, dans un fichier ou sur un réseau quelconque!  Ce qu'elle veut savoir en revanche, c'est quelle données elle doit envoyer vers le flux, et dans quel ordre.

      Or, le flux, comme je viens de te le dire, il peut prendre  pas mal de formes différentes, il faut donc que tu fournisse le flux dans lequel tu veux envoyer les données au moment où tu demande à la fonction de le faire ;)

      PCMRF a écrit:

      Par curiosité, j'ai modifié le code du cours de cette manière :

      Duree.h :

      #ifndef DEF_DUREE
      #define DEF_DUREE
      
      #include <iostream>
      class Duree
      {
      	int a_hours;
      	int a_minutes;
      	int a_seconds;
      
      public:
              /...
      	void show() const;
      };
      
      
      /...
      
      std::ostream &operator<<(std::ostream &flux, Duree const& duree);
      #endif DEF_DUREE

      Duree.cpp :

      #include "Duree.h"
      
      /...
      
      void Duree::show() const
      {
      	cout << a_hours << ":" << a_minutes << "." << a_seconds << endl;
      }
      
      /...
      
      ostream &operator<<(ostream &flux, Duree const& duree)
      {
      	duree.show();
      	return flux;
      }

      et j'obtient exactement le même résultat !

      Effectivement, tu obtiens un résultat sensiblement identique. 

      Cependant, tu n'imagines pas les restrictions que ce code impose!  Car, tel que tu l'écris, ton code impose que la durée soit affichée... sur la sortie standard.

      Et, dis moi: que crois tu qu'il va se passer le jour où tu voudras -- par exemple -- enregistrer la durée dans un fichier ?

      Que se passerait-il, selon toi, avec un code proche de

      int main(){
          Duree duree;
          /* on défini les heures, les minutes et les secondes */
          std::ofstream ofs{"fichier.txt"}; // ca, c'est un fichier
                                            // dans lequel je peux écrire
          // std::osfstream est une classe qui dérive de std::ostream, ce qui fait
          // que l'opérateur << fonctionne normalement pour le fichier
          ofs<<duree;
      }

      Tel qu'il est écrit, ton code va ... afficher les informations de durée sur la sortie standard, ce qui n'est -- clairement-- pas ce que tu  souhaitais, vu que tu voulais les faire afficher dans le fichier nommé "fichier.txt" :p

      -
      Edité par koala01 27 juillet 2020 à 13:47:38

      • 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
        27 juillet 2020 à 14:17:29

        OK j'ai compris, donc cette manière de faire est là pour apporter plus de "liberté" d'utilisation. On veut pouvoir utiliser ces chevrons vers n'importe quel flux / sortie, et pas seulement la console, donc même la nomenclature "afficher" pour la fonction n'est pas forcément adaptée.

        Merci, c'est très clair, surtout l'exemple avec le fichier ! :D 

        • Partager sur Facebook
        • Partager sur Twitter
          27 juillet 2020 à 15:30:35

          PCMRF a écrit:

          donc même la nomenclature "afficher" pour la fonction n'est pas forcément adaptée.

          Aahh, ca me fait plaisir que tu t'en sois rendu compte !!!

          Car, de fait, cette fonction n'affiche à proprement parler absolument rien.  Ce qu'elle fait, c'est ... envoyer les données dans le flux qui lui est fourni, sans s'inquiéter de l'usage que le flux pourra faire de ces données.

          Elle serait sans doute donc bien mieux nommée si elle s'appelait ... envoyer ;)

          • 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
            27 juillet 2020 à 17:42:58

            Corrigé et implémenté sans problème dans le TP sur les fractions.

            Thanks :)

            • Partager sur Facebook
            • Partager sur Twitter

            Le pourquoi du comment on surcharge l'opérateur <<

            × 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