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 :

Enregistrement d'une structure dans un fichier


Sujet :

C++

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre confirmé
    Homme Profil pro
    Technicien réseaux et télécoms
    Inscrit en
    Avril 2007
    Messages
    87
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 33
    Localisation : Belgique

    Informations professionnelles :
    Activité : Technicien réseaux et télécoms
    Secteur : High Tech - Produits et services télécom et Internet

    Informations forums :
    Inscription : Avril 2007
    Messages : 87
    Par défaut Enregistrement d'une structure dans un fichier
    Bonsoir,

    Je rencontre l'erreur suivante lorsque j'essaie d'enregistrer ma structure dans un fichier :

    tribaltime.cpp:55: erreur : C2679: binary '<<' : no operator found which takes a right-hand operand of type 'TribalTime::configurationMonde' (or there is no acceptable conversion)

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    void TribalTime::ajouterMonde(int numero, float vitesseMonde, float vitesseUnite)
    {
        std::ofstream fichierMondes("data/mondes.txt");
        if(fichierMondes)
        {
            struct configurationMonde mondeConfig = {numero, vitesseMonde, vitesseUnite};
     
            fichierMondes << mondeConfig;
        }
        else
        {
            QMessageBox::critical(this, tr("Erreur"), tr("Erreur lors de l'ouverture du fichier des mondes."));
        }
    }
    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
    #ifndef TRIBALTIME_H
    #define TRIBALTIME_H
     
    #include <QMainWindow>
    #include <sstream>
    #include <QtGui>
    #include <fstream>
     
    namespace Ui {
    class TribalTime;
    }
     
    class TribalTime : public QMainWindow
    {
        Q_OBJECT
     
        struct configurationMonde
        {
            int numero;
            float vitesseMonde;
            float vitesseUnite;
        };
     
    public:
        explicit TribalTime(QWidget *parent = 0);
        ~TribalTime();
       std::string getMonde() const;
       void setMonde(int m_monde);
     
    public slots:
       void aPropos();
       void ajouterMonde(int numero, float vitesseMonde, float vitesseUnite);
     
    private:
        Ui::TribalTime *ui;
        int monde;
        float vitesseMonde;
        float vitesseUnite;
        struct configurationMonde mondeConfig;
     
    };
     
    #endif // TRIBALTIME_H
    Merci d'avance !

  2. #2
    Inactif  


    Homme Profil pro
    Inscrit en
    Novembre 2008
    Messages
    5 288
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 49
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Secteur : Santé

    Informations forums :
    Inscription : Novembre 2008
    Messages : 5 288
    Par défaut
    Bonjour

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    struct configurationMonde mondeConfig = {numero, vitesseMonde, vitesseUnite};
    Ca fait quoi cette ligne pour toi ? En tout cas, c'est pas une définition de structure, ni une déclaration de variable. Et pourquoi ne pas passer directement tes variables dans le stream ?

    HS : Et j'ai du mal à voir comment tu conçois ta classe, ce qu'elle représente et ce que le service qu'elle doit rendre. Tu es sur de la conception de ta classe ?

  3. #3
    Membre Expert

    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Août 2004
    Messages
    1 391
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 34
    Localisation : France, Doubs (Franche Comté)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Août 2004
    Messages : 1 391
    Par défaut
    Bonjour,

    @gbdivers: C'est bel et bien une déclaration de variable et initialisation d'objet. C'est plus verbeux que nécessaire ici, mais ça reste valide.

    @OP: L'erreur te dit simplement que le compilateur ne sait pas comment il doit faire pour mettre un objet de type configurationMonde dans un flux. As tu écrit un fonction d'insertion dans les flux pour faire ca ? Si oui tu peux la montrer (notamment les scopes qui l'entoure : namespace/classe/etc).

  4. #4
    Inactif  


    Homme Profil pro
    Inscrit en
    Novembre 2008
    Messages
    5 288
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 49
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Secteur : Santé

    Informations forums :
    Inscription : Novembre 2008
    Messages : 5 288
    Par défaut
    @Flob90
    J'avais vu le struct configurationMonde mondeConfig; dans le .h mais je voyais pas de include pour une telle structure... je pensais que c'était une erreur, j'avais pas vu la neasted struct

  5. #5
    Membre Expert

    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Août 2004
    Messages
    1 391
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 34
    Localisation : France, Doubs (Franche Comté)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Août 2004
    Messages : 1 391
    Par défaut
    @gbdivers: J'avais pas vu la donnée membre nommé mondeConfig , du coup je suis pas certain que la ligne ai le comportement attendu par l'OP : masquage de la donnée membre par une variable local et pas une simple affectation. Et dans tout les cas c'est un élément de syntaxe superflus ici.

  6. #6
    Membre confirmé
    Homme Profil pro
    Technicien réseaux et télécoms
    Inscrit en
    Avril 2007
    Messages
    87
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 33
    Localisation : Belgique

    Informations professionnelles :
    Activité : Technicien réseaux et télécoms
    Secteur : High Tech - Produits et services télécom et Internet

    Informations forums :
    Inscription : Avril 2007
    Messages : 87
    Par défaut
    Citation Envoyé par Flob90 Voir le message
    Bonjour,

    @gbdivers: C'est bel et bien une déclaration de variable et initialisation d'objet. C'est plus verbeux que nécessaire ici, mais ça reste valide.

    @OP: L'erreur te dit simplement que le compilateur ne sait pas comment il doit faire pour mettre un objet de type configurationMonde dans un flux. As tu écrit un fonction d'insertion dans les flux pour faire ca ? Si oui tu peux la montrer (notamment les scopes qui l'entoure : namespace/classe/etc).
    Merci pour vos réponses !

    Non, je n'ai pas créé de telle fonction.
    Le but est de pouvoir ajouter/supprimer un monde facilement. J'avais vu en cours (de C), comment faire des listes chainées, d'où l'utilisation d'une structure pour avoir plus facile, mais j'ai un peu de mal à transposer ça en C++.

  7. #7
    Rédacteur
    Avatar de 3DArchi
    Profil pro
    Inscrit en
    Juin 2008
    Messages
    7 634
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2008
    Messages : 7 634
    Par défaut
    Salut,
    Les listes en C++, c'est std::list.
    Pour les entrées/sorties pour ses classes, cf Comment utiliser les flux pour afficher ou saisir mes objets ?. Ceci dit, il existe des bibliothèques pour la sérialisation : cf Boost.Serialisation.

    En C, il faut effectivement répérer struct. En C++ c'est inutile:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    class TribalTime : public QMainWindow
    {
        struct configurationMonde
        {
            int numero;
            float vitesseMonde;
            float vitesseUnite;
        };
     
    private:
        configurationMonde mondeConfig; // pas besoin de struct !!!
    Comme le dit Flob90, la variable locale mondeConfig masque la variable membre :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    void TribalTime::ajouterMonde(int numero, float vitesseMonde, float vitesseUnite)
    {
        std::ofstream fichierMondes("data/mondes.txt");
        if(fichierMondes)
        {
            configurationMonde mondeConfig = {numero, vitesseMonde, vitesseUnite}; // ici mondeConfig  masque la variable de même nom définie pour l'objet (cf .h)
     
            fichierMondes << mondeConfig;
        }
        else
        {
            QMessageBox::critical(this, tr("Erreur"), tr("Erreur lors de l'ouverture du fichier des mondes."));
        }
    }
    Tu fais une déclaration anticipée de TribalTime dans l'espace de nom Ui. Mais tu définis la classe en dehors de cet espace de nom. Je ne pense pas que ce soit souhaité, non ?
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    namespace Ui {
    class TribalTime;
    }
     
    class TribalTime : public QMainWindow // Attention, ce n'est pas la classe Ui::TribalTime
    {
    Je ne connais pas Qt, mais les en-têtes suivants sont inutiles dans le fichier .h : #include <sstream> et #include <fstream>. En revanche, tu as besoin de <string>. Il faut veiller à n'inclure que ce dont on a besoin => F.A.Q. Quels fichiers d'en-tête dois-je inclure ? et suivants.

  8. #8
    Membre confirmé
    Homme Profil pro
    Technicien réseaux et télécoms
    Inscrit en
    Avril 2007
    Messages
    87
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 33
    Localisation : Belgique

    Informations professionnelles :
    Activité : Technicien réseaux et télécoms
    Secteur : High Tech - Produits et services télécom et Internet

    Informations forums :
    Inscription : Avril 2007
    Messages : 87
    Par défaut
    Merci beaucoup pour tous les conseils !

    En réalité, j'ai besoin de <sstream> pour cette fonction :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    std::string TribalTime::getMonde() const
    {
        std::ostringstream flux;
        flux << this->monde;
        return flux.str();
    }
    Tu fais une déclaration anticipée de TribalTime dans l'espace de nom Ui. Mais tu définis la classe en dehors de cet espace de nom. Je ne pense pas que ce soit souhaité, non ?
    A vrai dire, c'est QtCreator qui m'a généré les fichiers, dont cette partie.

  9. #9
    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,
    Citation Envoyé par 3DArchi Voir le message
    Tu fais une déclaration anticipée de TribalTime dans l'espace de nom Ui. Mais tu définis la classe en dehors de cet espace de nom. Je ne pense pas que ce soit souhaité, non ?
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    namespace Ui {
    class TribalTime;
    }
     
    class TribalTime : public QMainWindow // Attention, ce n'est pas la classe Ui::TribalTime
    {
    .
    Non, en fait, c'est tout à fait juste

    Ce qui se passe, c'est que Ui::TribalTime est une classe "formulaire" générée par le parsing du .ui obtenu avec Qt Designer.

    L'une des solution (hormis l'héritage public) est de placer, tout simplement, un pointeur sur la classe directement dans une classe équivalente.

    Pour éviter les dépendances plus ou moins inutiles, on peut se contenter de la déclaration anticipée et de l'inclusion du fichier d'en-tête correspondant (ici : TribalTime_ui.h) dans le fichier d'implémentation.

    Nous aurions donc:
    • TribalTime.ui : fichier "Xml" contenant la description du formulaire
    • TribalTime_ui.h : définition de Ui::TribalTime auto générée
    • TribalTime.h : définition d'une classe utilisateur (TribalTime, hors de l'espace de nom Ui) contenant les fonctions "perso"
    • TribalTime.cpp : définition des fonctions "perso"
    Ceci dit...

    @Portus ==> Tu définis une structure de type ConfigMonde de telle manière à ce qu'elle contienne en réalité trois données distinctes :
    1. numero
    2. vitesseMonde
    3. vitesseUnite
    Si le compilateur sait très bien comment envoyer un entier ou un réel dans un flux grâce à l'opérateur "<<", il ne sait par contre absolument pas comment il doit écrire cette structure dans le même flux :

    Doit-il écrire d'abord le numéro, suivi de vitesseMonde puis de vitesseUnite, ou doit il le faire dans un ordre différent

    Doit-il ajouter des informations supplémentaire, pour obtenir un résultat proche de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    [monde]
    numero : XXX
    vitesse monde : YY.zz
    vitesse unite : aa.bb
    ou dans un format "xml", ou autre

    Comme tu n'as rien dit au compilateur, qui n'est qu'un brave petit soldat ne prenant aucune initiative, il réagit de la seule manière "correcte" selon lui : il t'indique qu'il ne connait pas l'opérateur << pour ta structure.

    Tu dois donc veiller à fournir l'opérateur << adéquat

    Selon le cas, cela prendra soit la forme de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    // opérateur << pour "n'importe quel flux"
    std::ostream & operator << (std::ostream & os, ConfigMonde const & cm)
    {
       // ici le format à utiliser pour écrire les données
    }
    soit la forme de

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    // opérateur << spécifique à un fichier
    std::ofstream & operator << (std::ofstream & os, ConfigMonde const & cm)
    {
       // ici le format à utiliser pour écrire les données
    }
    N'oublie pas que, si tu arrives à écrire dans un flux quelconque, il est sans doute utile de pouvoir également... lire depuis un flux similaire (car, autrement, il te sera impossible de récupérer l'information par la suite )
    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

Discussions similaires

  1. Enregistrer une structure dans un fichier txt
    Par SLF153 dans le forum MATLAB
    Réponses: 4
    Dernier message: 22/03/2011, 13h24
  2. enregistrer une structure dans un fichier
    Par Namson dans le forum C
    Réponses: 1
    Dernier message: 21/02/2009, 23h31
  3. Réponses: 17
    Dernier message: 09/03/2007, 18h13
  4. stocker une structure dans un fichier ini?
    Par Mickey.jet dans le forum C
    Réponses: 6
    Dernier message: 13/09/2006, 16h57
  5. copier une structure dans un fichier
    Par brute dans le forum MFC
    Réponses: 18
    Dernier message: 10/03/2006, 14h30

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