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

Langage C++ Discussion :

Ajouter une en-tete à un ostream


Sujet :

Langage C++

  1. #1
    Membre à l'essai
    Profil pro
    Inscrit en
    Juin 2004
    Messages
    37
    Détails du profil
    Informations personnelles :
    Âge : 40
    Localisation : France

    Informations forums :
    Inscription : Juin 2004
    Messages : 37
    Points : 19
    Points
    19
    Par défaut Ajouter une en-tete à un ostream
    Bonjour,

    Je vous ecrit car j'essaye de developper une classe proprement (pour une fois) dans laquelle je donne au constructeur un parametre de type "ostream&" avec cout comme parametre par defaut histoire de pouvoir rediriger par la suite tous les messages de ma classe vers le flux que je veux (un fichier de log à la place de la sortie standard par exemple).

    Voici en exemple le constructeur simplifié avec vous l'aurez compris les deux données membres declarées precedemment en private dans la classe :

    CCamera(int indexCam, std::ostream& stream=std::cout)
    : m_stream(stream),
    m_indexCam(indexCam)
    {}
    Ceci fonctionne parfaitement et j'ecris tous mes message sous la forme :

    m_stream << "exemple sortie" << std::endl;
    Maintenant j'ai un peu reflechi et j'aimerai faire quelques chose de mieux. Je m'explique : je voudrais que, a chaque fois que j'utilise mon "m_stream", il se rajoute en en-tete du message que je vais rediriger, un message identifiant d'ou vient le message.

    En clair j'aimerais que pour cette classe camera qui sera instanciée avec indexCam=N par exemple, quand j'utilise la ligne de code precedente, au lieu d'avoir dans mon flux : "exemple sortie" j'ai quelques chose du style : "CAMERA N : exemple sortie"

    J'ai pensé a creer une classe CMyStream et à redefinir l'operateur << mais je ne sais pas vraiment comment m'y prendre.

    Dois-je deriver ma classe de ostream histoire de pouvoir prendre avantage de toutes le fonctions membres existantes deja ?

    Dois plutot juste faire une classe basique sans forcement deriver de ostream ?

    Bref si vous avez des conseils concernant ce type de besoin ou une piste a explorer je vous en serait reconnaissant :-)

    Merci de votre aide à bientot !!!

  2. #2
    Expert éminent sénior
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 614
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 614
    Points : 30 626
    Points
    30 626
    Par défaut
    Salut, et bienvenue sur le forum

    Typiquement, tu peux faire appel à tout membre quelqu'en soit la visibilité, dans le constructeur de ta classe, pour autant :
    • que ce ne soit pas un membre privé de la classe parent (dans le cadre d'un héritage)
    • que ce ne soit pas un membre d'une classe enfant (dans le cadre d'un héritage)
    Si, donc, tu dispose d'un membre nommé "numero" ou "id", par exemple dans ta classe camera et permettant d'identifier une caméra parmi d'autres, tu pourras envisager l'écriture d'un code proche de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    stream<< "ceci est la camera "<<numero
          <<" et son exemple de constructeur";
    pour autant que l'opérateur << existe pour le type de numero (ce qui est le cas pour l'ensemble des types primitifs)...

    Tout ce à quoi il te faudra veiller, c'est à ce que le membre en question soit correctement initialisé avant d'essayer d'en envoyer la valeur dans le flux
    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

  3. #3
    Membre à l'essai
    Profil pro
    Inscrit en
    Juin 2004
    Messages
    37
    Détails du profil
    Informations personnelles :
    Âge : 40
    Localisation : France

    Informations forums :
    Inscription : Juin 2004
    Messages : 37
    Points : 19
    Points
    19
    Par défaut
    Salut,

    Merci pour ta reponse rapide mais ma question ne concernait pas l'insertion de ma donnée membre dans le flux ce qui n'est effectivement pas un probleme.

    Desolé pour mon message un peu long qui doit etre un peu confus mais il s'agirait en fait de definir un nouveau flux (comme le cout utilisé courrament) qui ajouterais une en tete à tous les messages que j'enverrai dans le flux.

    Est-ce possible ? Je me doute que oui mais je ne sais pas trop comment aborder la question...

    Merci :-)

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

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 614
    Points : 30 626
    Points
    30 626
    Par défaut
    Hé bien, selon le cas, tu peux envisager une fonction libre / statique de classe / particulière dans une classe donnée dans laquelle tu crées toi-même l'en-tête de ton flux...

    Une fonction libre peut prendre 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
    /* voici une fonction libre renvoyant un flux de sortie
     * @in none
     * @out objet de type ostream
     *
     * !!! le flux étant créé dans la fonction, il doit être renvoyé par valeur
     * et non par référence, ce qui  implique une copie de l'objet si le compilateur
     * ne supporte pas (N)RVO
     */
    std::ostream createStream()
    {
        std::ostream os;
        os<<"Ceci sera l'en-tête du flux"<<std::endl;
        return os;
    }
    Dans une classe, cela pourrait prendre la forme d'une fonction statique proche de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    class MyClass
    {
        public:
        /* fonction statique permettant de rajouter l'en-tête
         * dans n'importe quel flux existant
         */
        static void createHeader(std::ostream& os)
        {
            os<<"Ceci sera l'en-tête du flux"<<std::endl;
        }
    };
    Enfin, tu pourrais envisager d' "encapsuler" le flux en tant que membre d'une classe, et de créer l'en-tête au niveau du constructeur de cette classe
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    class MyFileWriter
    {
        public:
            MyFileWriter(std::string const& f):filename_(f),os(f.c_str())
            {
                os<<"Ceci  sera l'en-tête du flux (qui  est un fichier ici)"
                  <<std::endl;
            }
            std::ofstream& stream(){return os;}
            std::string filename() const{return filename_;}
        private:
            std::string filename_;
            std::ofstream os;
    };
    Et ce ne sont bien sur que les premières idées qui m'ont traversé l'esprit
    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 à l'essai
    Profil pro
    Inscrit en
    Juin 2004
    Messages
    37
    Détails du profil
    Informations personnelles :
    Âge : 40
    Localisation : France

    Informations forums :
    Inscription : Juin 2004
    Messages : 37
    Points : 19
    Points
    19
    Par défaut
    Rebonjour,

    Ok je comprends ce que tu veux dire (bien que la syntaxe du dernier exemple ne me soit pas familiere) ;-)

    Or j'imagine que tes exemples sont la pour creer un flux et/ou ecrire dedans lors de la premiere utilisation.

    J'aurais voulu avoir en fait dans la classe que je vais utiliser (mais peut importe que soit une classe ou non) une donnée membre que je puisse utiliser comme le classique "cout".

    A savoir qu'il me rajoute cette fameuse en tete a chaque fois que j'utilise le flux.

    Voici ce que j'ai fait pour l'instant mais qui bien sur ne compile pas, c'est juste pour te montrer l'esprit :

    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
     
    class CMyStream
    {
        private:
     
    	string m_header;
    	ostream& m_stream;
     
    	string m_spacing;
     
        public:
     
    	CMyStream(string header, ostream & stream=cout, string spacing=string(" "))
    	:m_header(header),
    	 m_stream(stream),
    	 m_spacing(spacing)
    	{}
     
    	~CMyStream() {};
     
    	ostream& operator<<(ostream & streamIN)
    	{
    		return m_stream << m_header << m_spacing << streamIN;
    	}
    };
    Le but est de pouvoir utiliser une instance de cette classe comme le "cout" habituel.

    cad :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    monInstanceDeCMyStream << "test" << endl;
    et que lors de l'affichage il me rajoute au debut le contenu de m_header.

    Le probleme quand je fais ca est que bien sur à chaque fois que j'essaye d'utiliser l'operateur << avec un type de base il m'envoie bouler en me disant que ma fonction candidate est la fonction membre definie mais que la conversion n'est pas possible.

    J'ai essayé de fire deriver cette classe de la classe ostream mais sans succès (probleme de constructeur private j'imagine)...

    J'ai peut etre du mal a etre clair dsl

  6. #6
    Rédacteur/Modérateur
    Avatar de JolyLoic
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2004
    Messages
    5 463
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 49
    Localisation : France, Yvelines (Île de France)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Août 2004
    Messages : 5 463
    Points : 16 213
    Points
    16 213
    Par défaut
    Ce genre de chose se fait généralement en dérivant du streambuffer. Mais il existe un framework pour manipuler ainsi les flux plus aisément : http://www.boost.org/doc/libs/1_39_0...doc/index.html
    Ma session aux Microsoft TechDays 2013 : Développer en natif avec C++11.
    Celle des Microsoft TechDays 2014 : Bonnes pratiques pour apprivoiser le C++11 avec Visual C++
    Et celle des Microsoft TechDays 2015 : Visual C++ 2015 : voyage à la découverte d'un nouveau monde
    Je donne des formations au C++ en entreprise, n'hésitez pas à me contacter.

  7. #7
    Membre à l'essai
    Profil pro
    Inscrit en
    Juin 2004
    Messages
    37
    Détails du profil
    Informations personnelles :
    Âge : 40
    Localisation : France

    Informations forums :
    Inscription : Juin 2004
    Messages : 37
    Points : 19
    Points
    19
    Par défaut
    Merci beaucoup pour cette piste,

    apres un peu de temp passé à rechercher sur notre moteur de recherche préféré et m'etre perdu dans beaucoup de lignes de codes non commentées et non expliquées j'ai fini par trouver ca :
    http://savingyoutime.wordpress.com/2...logging-class/

    Ceci semble correspondre tout a fait a ce que je recherche, je vais essayer de comprendre et de jouer avec cet exemple et voir si j'arrive à faire ce que je voulais. Je vous tiendrai au courant.

    Si vous avez des remarques a faire quand au contenu de ce lien, ca serait avec plaisir.

    Merci encore et @ bientot j'espere !

  8. #8
    Membre à l'essai
    Profil pro
    Inscrit en
    Juin 2004
    Messages
    37
    Détails du profil
    Informations personnelles :
    Âge : 40
    Localisation : France

    Informations forums :
    Inscription : Juin 2004
    Messages : 37
    Points : 19
    Points
    19
    Par défaut
    Rebonjour,

    Je reviens vers vous pour vous tenir au courant de comment j'ai fini par resoudre ma problematique.

    Je suis donc parti sur la piste de redefinir un streambuf qui ajoute en en-tete de mes sorties, pour chaque nouvelle ligne, un string predefini.

    Le lien precedent que j'avais trouvé s'est en fait révélé peu utile puisqu'il injecte l'en-tete dans le cout directement a partir de la fonction sync() et qu'en plus il m'obligeait a utiliser rdbuf pour redefinir le streambuf du cout ce qui avait pour consequence d'ajouter mon en tete meme dans me utilisation du cout en dehors de ce contexte... bref, pas top.

    Je suis enfin tombé sur cet exemple en bas de la page duquel je me suis servi et que j'ai un peu adapté : http://www.informatik.uni-konstanz.de/~kuehl/iostream/

    Il presente l'avantage de definir un streambuf qui va encapsuler le streambuf d'origine du flux que l'on veut modifier et de proceder a l'ajout de l'en tete dans la fonction overflow apres detection de la nouvelle ligne ('\n').

    Ainsi on ne modifie pas directement le streambuf du flux visé (le streambuf cout reste intact) mais on defini un nouveau ostream qui va utiliser le streambuf qui encapsule le streambuf du cout (ou tout autre flux) et qui va ajouter l'en tete dans la fonction overflow avant d'appeler celle du cout.

    Voici la classe que j'ai defini a partir de l'exemple (tres peu de modifs si ce n'est la possibilité de definir le flux d'origine a partir duquel on va encapsuler le streambuf (ainsi ca peut tres bien etre un ostringstream par exemple), l'utilisation d'un string pour le header et le fait d'ignorer les istream qui ne presentait pas d'interet dans mon cas) :

    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
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
     
    class CMyStreambuf: public streambuf
    {
        private:
    	streambuf *m_sbuf; // the actual streambuf used to read and write chars
    	string m_header; // the prefix
    	bool m_newLine; // remember whether we are at a new line
     
        protected:
    	int	overflow(int);
    	int	sync();
     
        public:
    	CMyStreambuf(streambuf *sb, string header);
    	~CMyStreambuf();
    };
     
     
    CMyStreambuf::CMyStreambuf(streambuf *sb, string header)
    :streambuf(),
     m_sbuf(sb),
     m_header(header),
     m_newLine(true)
    {
    	setp(0, 0);
    }
     
     
    CMyStreambuf::~CMyStreambuf() {}
     
     
    int CMyStreambuf::overflow(int c)
    {
    	if (c != EOF)
    	{
    		if (m_newLine)
    			if (m_sbuf->sputn(m_header.c_str(), m_header.size()) != m_header.size())
    				return EOF;
    			else
    				m_newLine = false;
     
    		int rc = m_sbuf->sputc(c);
     
    		if (c == '\n')
    			m_newLine = true;
    		return rc;
    	}
    	return 0;
    }
     
     
    int CMyStreambuf::sync()
    {
    	//m_sbuf->sync();
    	return 0;
    }
    Et voici la classe qui redefini un nouveau ostream et qui extrait le streambuf du ostream d'origine pour creer un "MyStreamBuf" utilisé dans l'instance créée :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
     
    // This is the output stream; its function is to format data (using mainly the <<
    // operator) and send it to a streambuf to be stored and written to the output.
     
    class CMyStream : public ostream
    {
        public:
    	CMyStream(string header=string(""), ostream& stream=cout)
    	:ostream(new CMyStreambuf(stream.rdbuf(),header)),
    	 ios(0)
    	{}
     
    	~CMyStream() { delete rdbuf(); }
    };

    Ainsi il sera facile de definir un nouveau CMyStream par :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
     
    // flux dans lequel on veut injecter nos sorties avec en tete (ca aurait pu etre "cout"
    // tout simplement mais on voit que ca marche aussi avec des ostringstream)
    ostringstream oss;
     
    string header("Ceci est mon en-tete : ")
     
    // ici j'utilise un new pour le mettre en memoire dynamique au cas ou l'on defini
    // ce stream dans un constructeur par exemple et qu'il doit etre utilisé en dehors
    // du bloc courant
    CMyStream& myStream=*(new CMyStream(header, oss))
    Voila, j'espere que j'ai ete assez clair et que cela pourra aider certains d'entre vous, ca m'a demandé un peu de temps a explorer la doc des ostream et streambuf pour comprendre mais je pense que ca vaut le coup.

    Si vous avez des commentaires n'hesitez pas, je pars dans le monde des exceptions et apres je serai pret a commencer a programmer mon projet pour de bon...

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Réponses: 0
    Dernier message: 01/08/2013, 16h08
  2. Réponses: 0
    Dernier message: 17/01/2012, 15h54
  3. [C#] ajouter une image dynamiquement
    Par h_imane dans le forum ASP.NET
    Réponses: 4
    Dernier message: 21/04/2004, 11h27
  4. [Plugin] Ajouter une option au menu contextuel ?
    Par relivio dans le forum Eclipse Platform
    Réponses: 2
    Dernier message: 22/03/2004, 16h18
  5. Ajouter une aide
    Par Mailgifson dans le forum C++Builder
    Réponses: 5
    Dernier message: 12/06/2002, 13h32

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