IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

 C++ Discussion :

Difficulte de comprehension des streams et de l'operateur <<


Sujet :

C++

  1. #1
    Membre averti
    Profil pro
    Inscrit en
    Juin 2010
    Messages
    24
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2010
    Messages : 24
    Par défaut Difficulte de comprehension des streams et de l'operateur <<
    Bonjour a tous,

    Je viens vers vous car j'ai une difficulté a comprendre les streams et l'utilisation de l'operateur <<.

    J'ai saisi que ostream se base sur le type char, or lorsque je fais

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     
    	 Person p;
    	 p.name = "martin";
    	 p.firstname = "philippe";
    	 p.age = 29;
    	 char * c;
    	 c << p;
    ca ne fonctionne pas. sachant que la classe Person possède

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    std::ostream& operator<<(std::ostream& out, Person & p){
    	out << p.name << p.firstname << p.age;
    	return out;
    }
    Est-il possible de récupérer mon ostream pour utiliser via ios::rdbuf la méthode streambuf::sgetc. Qui me permettrait de récupérer en mémoire les les caractères/bytes de mon objet.

    Merci d'avance pour vos reponses.

  2. #2
    Membre émérite

    Profil pro
    Inscrit en
    Décembre 2008
    Messages
    533
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2008
    Messages : 533
    Par défaut
    Je ne comprends pas trop ce que tu veux faire avec ton char* c.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
     
    #include <iostream>
    #include <sstream>
     
    struct Person { std::string name, firstname; int age; };
    std::ostream& operator<<(std::ostream& out, Person & p) {
    	out << p.name << p.firstname << p.age;
    	return out;
    }
     
    int main()
    {
     Person p;
     p.name = "martin";
     p.firstname = "philippe";
     p.age = 29;
     
     std::stringstream ss;
     ss << p;
     
     std::cout << ss.str() << std::endl;
     
     return 0;
     
    }
    Affiche : martinphilippe29

  3. #3
    Inactif  


    Homme Profil pro
    Doctorant sécurité informatique — Diplômé master Droit/Économie/Gestion
    Inscrit en
    Décembre 2011
    Messages
    9 026
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 32
    Localisation : France, Loire (Rhône Alpes)

    Informations professionnelles :
    Activité : Doctorant sécurité informatique — Diplômé master Droit/Économie/Gestion
    Secteur : Enseignement

    Informations forums :
    Inscription : Décembre 2011
    Messages : 9 026
    Par défaut
    Peut-être préfèrera-t-il ceci :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    char * operator<<( (char *) & retour, Person & p){
             char * retour = new char[strlen(p.name) + strlen(p.firstname) + 1] ;
    	strcpy(retour, p.name);
            char * tmp = retour + strlen(p.name);
            strcpy(tmp, p.firstname);
    	return retour;
    }
    Mais pourquoi utiliser un char * et non un string ?
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    const std::string & operator<<(std::string & retour, Person & p){
             retour = "";
             retour += p.name;
              retour += p.firstname;
    	return retour;
    }

  4. #4
    Expert éminent
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 644
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 53
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 644
    Par défaut
    Salut,

    En fait, l'opérateur << est un opérateur binaire comme il y en a tant d'autres (+, -, *, /, leurs équivalents d'affectation, <, >, == et ceux que j'oublie ).

    C'est à dire qu'il faut juste lui fournir deux opérandes : le premier à gauche, le second à droite.

    Comme tous les autres opérateurs du même type, il fera exactement ce que tu pourras lui demander de faire en fonction des deux arguments qu'il obtiendra

    Il faut savoir que ce n'est pas l'opérateur << qui est responsable du comportement des flux, mais bien que c'est justement le fait qu'on lui passe, en tant que premier paramètre, un flux de sortie qui sera responsable du comportement que l'on observe sur la sortie standard ou dans un fichier.

    Ceux qui ont choisi l'opérateur << comme opérateur pour les flux auraient tout aussi bien pu choisir n'importe quel autre, comme le montre l'utilisation de l'opérateur & dans boost::serialization

    Ensuite, il faut savoir que ce n'est pas avec un char * que l'opérateur << est spécialisé pour les flux, mais... avec la std::string (qui est un typedef de std::basic_string<char>) et que l'on profite "simplement" d'un comportement de conversion implicite de const char * en std::string grâce au constructeur qui va bien (en gros, basic_string::basic_string(charType *) )

    Quand tu écris un code proche de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    std::ostream& operator<<(std::ostream& out, Person & p){
    	out << p.name << p.firstname << p.age;
    	return out;
    }
    tu indiques que l'opérateur << doit prendre une référence sur un flux de sortie comme premier paramètre et une référence (qui devrait d'ailleurs être déclarée constante, vu que l'objet ne sera pas modifié par la fonction ) sur un objet de type Person et qui renvoie... une référence sur le flux de sortie (de manière à pouvoir chainer les opérations de sorties vers le flux).

    std::ostream n'a strictement rien à voir avec un quelconque char * car d'un coté tu as bel et bien une classe, c'est à dire une structure complexe composée de données (en gros, un buffer + une série d'informations particulière) et de fonctions membres, alors que char * représente... un pointeur sur un caractère, et qu'un caractère n'est jamais qu'une valeur numérique codée sur un certain nombre de bits (et devant donc se trouver dans une fourchette de valeurs particulières)

    En outre, il est fortement déconseillé d'utiliser des char * pour la représentation de chaines de caractères en C++, essentiellement parce que leur gestion est particulièrement délicate (respect du nombre de caractères que l'on peut utiliser, utilisation des fonctions comme strcpy, strcmp, strlen et autres, gestion dynamique de la mémoire allouée à la chaine de caractères, et j'en passe).

    En C++, il existe une classe qui prend tout cela en charge pour toi, et qui est bien plus fiable que tout ce que tu pourras coder dans un délais raisonnable si tu n'est pas excessivement bon en C++ : la classe string, disponible dans l'espace de noms std (comme tout ce qui est fourni par le standard) par inclusion du fichier d'en-tête <string>.

    Parmi les flux de sortie qui héritent de std::ofstream, il y en a cependant un qui devrait t'intéresser au plus haut point, surtout que tu voudrais sans doute arriver à convertir l'age de ta personne en chaine de caractères

    Le flux dont je te parle est std::ostringstream qui permet, à condition de fournir l'opérateur << adéquat (exactement comme tu l'as fait, en plus) de convertir "n'importe quoi" en chaine de caractères

    Ce flux dispose, entre autres, d'une fonction membre str() qui a pour effet de... renvoyer une std::string

    Tu pourrais donc parfaitement avoir quelque chose qui prendrait une forme proche de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    /* soit la structure "Person" ressemblant à  */
    struct Person
    {
        std::string name;
        std::strintg firstname;
        int age;
    };
    /* et l'opérateur << "qui va bien" ressemblant à */ 
    std::ostream& operator<<(std::ostream& out, Person & p)
    {
    	out << p.name << p.firstname << p.age;
    	return out;
    }
    /* tu pourais très bien utiliser le tout sous une forme proche de */
    int main()
    {
        Person p;
        p.name = "martin";
        p.firstname = "philippe";
        p.age = 29;
        std::stringstream ss;
        /* on introduit la personne dans le flux de conversion
         * mais ss pourrait, grace à l'opérateur << utilisant un ostream,
         * tout aussi bien être la sortie standard (cout) ou un fichier (ofstream)
         */
        ss<<p;
        /* il est possible de récupérer une chaine de caractères au départ du
         *  flux si c'est un std::(o)stringstream :
         */
        std::string str = ss.str();
        /* et, en cas de besoin, il est possible (pour la compatibilité avec C uniquement ;) 
         * de récupérer une chaine de caractères "C style" grace à la fonction
         * membre de la classe string c_str()
         */
        const char * charPtr = str.c_str();
        /* ... */
        return 0; 
    }
    Hope it helps
    A méditer: La solution la plus simple est toujours la moins compliquée
    Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
    Compiler Gcc sous windows avec MinGW
    Coder efficacement en C++ : dans les bacs le 17 février 2014
    mon tout nouveau blog

  5. #5
    Membre averti
    Profil pro
    Inscrit en
    Juin 2010
    Messages
    24
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2010
    Messages : 24
    Par défaut
    Merci pour toutes ces informations.

    J'ai choisis de ne pas utiliser std::stringstream car je n'etais pas sur de pouvoir recuperer mes donnees en utilisant std::istream par la suite.

    si jai un string avec "martinphilippe29", en effet comment faire pour recupere le prenom et le nom separement ? J'ai donc pense qu'avec un char* j'aurai plus de chance

  6. #6
    Membre averti
    Profil pro
    Inscrit en
    Juin 2010
    Messages
    24
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2010
    Messages : 24
    Par défaut
    il y a encore une grosse zone d'ombre dans mon esprit.

    Dans ce code :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    std::ostream& operator<<(std::ostream& out, Person & p){
    	out << p.name << p.firstname << p.age;
    	return out;
    }
    Que se passe-t-il a ce niveau : out << p.name & out << p.age

    p.name est du type std::string, out est un ostream et p.age est lui un int.
    Quelle conversion s'execute ? Aucune pour p.name ? Une conversion de p.age en std::string ? Aussi out conserve-t-il le \0 de fin de string ?

    Lorsque j'utilise la methode str() sur le stringstream, comment la nouvelle string peut conserver la "connaissance" des trois elements qui la compose ?

    je suis encore un peu dans le flou

  7. #7
    Inactif  


    Homme Profil pro
    Doctorant sécurité informatique — Diplômé master Droit/Économie/Gestion
    Inscrit en
    Décembre 2011
    Messages
    9 026
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 32
    Localisation : France, Loire (Rhône Alpes)

    Informations professionnelles :
    Activité : Doctorant sécurité informatique — Diplômé master Droit/Économie/Gestion
    Secteur : Enseignement

    Informations forums :
    Inscription : Décembre 2011
    Messages : 9 026
    Par défaut
    Il ne me semble pas que ostream fasse une distinction entre les éléments qui le composent.
    L'opérateur '<<(std::ostream & out, Type x)" est défini pour chaque type.
    Je ne sais pas vraiment comment sont implémentés les flux mais théoriquement on n'a pas besoin de savoir ce qui se cache derrière.

    EDIT :
    Citation Envoyé par http://www.cplusplus.com/reference/iostream/ostream/
    Formatted output
    These member functions interpret and format the data to be written as sequences of characters. These type of operation is performed using member and global functions that overload the insertion operator (operator<<)
    Fin Edit.

    Par contre, je suis sûr que lors du .str(), tu obtiendras un string qui sera la concaténation de tous ces éléments. Tu n'auras donc plus de distinctions entre les différents éléments.

    Après il faut savoir ce que tu cherches à faire ensuite avec ce que tu obtiendras.

  8. #8
    Membre très actif
    Profil pro
    professeur des universités à la retraite
    Inscrit en
    Août 2008
    Messages
    364
    Détails du profil
    Informations personnelles :
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : professeur des universités à la retraite

    Informations forums :
    Inscription : Août 2008
    Messages : 364
    Par défaut
    Il va de soi que tu peux séparer les trois éléments à ta guise dans ta str, par exemple pour les séparer par une espace tu peux modifier ta surcharge du flux ainsi :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
        /* et l'opérateur << "qui va bien" ressemblant à */
        std::ostream& operator<<(std::ostream& out, Person & p)
        {
            out << p.name << " " << p.firstname << " " << p.age;
            return out;
        }

  9. #9
    Inactif  


    Homme Profil pro
    Doctorant sécurité informatique — Diplômé master Droit/Économie/Gestion
    Inscrit en
    Décembre 2011
    Messages
    9 026
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 32
    Localisation : France, Loire (Rhône Alpes)

    Informations professionnelles :
    Activité : Doctorant sécurité informatique — Diplômé master Droit/Économie/Gestion
    Secteur : Enseignement

    Informations forums :
    Inscription : Décembre 2011
    Messages : 9 026
    Par défaut
    Citation Envoyé par ptyxs Voir le message
    Il va de soi que tu peux séparer les trois éléments à ta guise dans ta str, par exemple pour les séparer par une espace tu peux modifier ta surcharge du flux ainsi :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
        /* et l'opérateur << "qui va bien" ressemblant à */
        std::ostream& operator<<(std::ostream& out, Person & p)
        {
            out << p.name << " " << p.firstname << " " << p.age;
            return out;
        }
    Je ne suis pas d'accord.
    Et si la personne s'appelle De La Fontaine ?

    Il faudrait donc utiliser un caractère comme '\t' pour séparer les différents éléments.

    Ou alors créer sa propre classe contenant un nom, un prénom et un âge.
    On redéfini les opérateurs de flux, on fait des getters pour le nom, le prénom et l'âge.
    En membres privé on pourra avoir :
    - un string contenant le nom, prénom et âge.
    - l'âge en int.
    - la taille du nom
    - la taille du prénom

    Et avec ceci on pourra pratiquement tout faire :
    - obtenir un string ou un char * contenant toutes les informations ;
    - obtenir les différents éléments séparément.

  10. #10
    Rédacteur/Modérateur


    Homme Profil pro
    Network game programmer
    Inscrit en
    Juin 2010
    Messages
    7 147
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 38
    Localisation : Canada

    Informations professionnelles :
    Activité : Network game programmer

    Informations forums :
    Inscription : Juin 2010
    Messages : 7 147
    Billets dans le blog
    4
    Par défaut
    Citation Envoyé par Logan5 Voir le message
    Merci pour toutes ces informations.

    J'ai choisis de ne pas utiliser std::stringstream car je n'etais pas sur de pouvoir recuperer mes donnees en utilisant std::istream par la suite.

    si jai un string avec "martinphilippe29", en effet comment faire pour recupere le prenom et le nom separement ? J'ai donc pense qu'avec un char* j'aurai plus de chance
    Que tu utilises un string, stream ou char* est strictement identique : il est absolument impossible de découper une chaîne dont on a pas définit de séparateur (un caractère particulier, un nombre de caractères, ...). Ce qui est ton cas dans ce que tu présentes.

    Si tu veux pouvoir les redécouper, tu dois définir une règle de découpage, et la règle inverse sera celle utilisée pour la concaténation.

    il y a encore une grosse zone d'ombre dans mon esprit.

    Dans ce code :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    std::ostream& operator<<(std::ostream& out, Person & p){
    	out << p.name << p.firstname << p.age;
    	return out;
    }
    Que se passe-t-il a ce niveau : out << p.name & out << p.age

    p.name est du type std::string, out est un ostream et p.age est lui un int.
    Quelle conversion s'execute ? Aucune pour p.name ? Une conversion de p.age en std::string ? Aussi out conserve-t-il le \0 de fin de string ?
    Honnêtement, je ne sais pas, mais la bonne nouvelle c'est : on en a rien à faire !
    L'opérateur << est déjà surchargé correctement pour concaténer string, char* et int (entre autre).
    Tout ce dont tu as à te soucier c'est de l'utiliser.
    Pensez à consulter la FAQ ou les cours et tutoriels de la section C++.
    Un peu de programmation réseau ?
    Aucune aide via MP ne sera dispensée. Merci d'utiliser les forums prévus à cet effet.

  11. #11
    Membre très actif
    Profil pro
    professeur des universités à la retraite
    Inscrit en
    Août 2008
    Messages
    364
    Détails du profil
    Informations personnelles :
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : professeur des universités à la retraite

    Informations forums :
    Inscription : Août 2008
    Messages : 364
    Par défaut
    Citation Envoyé par Neckara Voir le message
    Je ne suis pas d'accord.
    Et si la personne s'appelle De La Fontaine ?

    Il faudrait donc utiliser un caractère comme '\t' pour séparer les différents éléments.
    Bien entendu ! J'ai bien précisé qu'il pourrait modifier à sa guise et que ceci n'était qu'un exemple : à lui ensuite d'opérer en fonction de ses données et de ce qu'il souhaite en faire !!

  12. #12
    Membre averti
    Profil pro
    Inscrit en
    Juin 2010
    Messages
    24
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2010
    Messages : 24
    Par défaut
    Ça m'aide beaucoup de savoir que ostream a besoin d'une regle de decoupage entre les elements qu'on lui transmet. Je pensais que chaque appelle a << etait flagué

    Par le passe j'ai utilise Qt avec QDataStream et je n'avais pas a me soucier de cette separation. Je suppose que c'est intégré !

  13. #13
    Rédacteur/Modérateur


    Homme Profil pro
    Network game programmer
    Inscrit en
    Juin 2010
    Messages
    7 147
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 38
    Localisation : Canada

    Informations professionnelles :
    Activité : Network game programmer

    Informations forums :
    Inscription : Juin 2010
    Messages : 7 147
    Billets dans le blog
    4
    Par défaut
    J'ignore ce que fait QDataStream, mais std::ostream ne fait rien d'autre que ce qu'on lui demande : enregistrer un flux.
    Ce n'est pas à lui de décider de séparer chaque enregistrement consécutif avec un flag, caractère spécial ou quoi que ce soit d'autre.
    Pensez à consulter la FAQ ou les cours et tutoriels de la section C++.
    Un peu de programmation réseau ?
    Aucune aide via MP ne sera dispensée. Merci d'utiliser les forums prévus à cet effet.

  14. #14
    Membre Expert
    Avatar de Joel F
    Homme Profil pro
    Chercheur en informatique
    Inscrit en
    Septembre 2002
    Messages
    918
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 45
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Chercheur en informatique
    Secteur : Service public

    Informations forums :
    Inscription : Septembre 2002
    Messages : 918
    Par défaut
    cout << x << y << z:

    s'evalue comme


    ((cout << x) << y) << z:

    et comme cout << x renvoit cout , je te laisse faire 1+1

Discussions similaires

  1. event sur des streams de socket
    Par quicky2000 dans le forum Entrée/Sortie
    Réponses: 4
    Dernier message: 02/11/2007, 16h34
  2. Réponses: 0
    Dernier message: 17/09/2007, 14h21
  3. Probleme de comprehension des masques
    Par dduke dans le forum Développement
    Réponses: 3
    Dernier message: 08/01/2007, 18h38
  4. Difficulte a afficher des hexadecimale
    Par Battosaiii dans le forum C
    Réponses: 3
    Dernier message: 19/03/2006, 11h29
  5. Réponses: 3
    Dernier message: 04/09/2002, 09h42

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo