Partage
  • Partager sur Facebook
  • Partager sur Twitter

Constructeur et fonctions

Comment faire?

Sujet résolu
    29 mars 2008 à 17:51:09

    Bonjour,
    Voilà, j'ai, dans mon programme, une classe contenant un attribut m_configuration de type Config
    Dans la liste d'initialisation du constructeur de cette classe, j'ai mis
    1. m_configuration()

    Dans la classe Config, j'ai tout les attributs et les méthodes concernant la configuration du programme (langue, design...), j'ai donc créé deux classes: Langue et Design dont les constructeurs sont respectivement:
    1. Langue(std::string langue_jeu);

    et
    1. Design(std::string dossier_design);

    J'ai donc besoin d'avoir la langue du jeu et le dossier contenant les images du design.Ces informations sont contenues dans un fichier.
    J'ai donc fait une fonction lireConfig() qui permet de récuperer ces informations et de les mettres dans les variables
    1. std::string m_dossierDesign;
    2. std::string m_langueJeu;

    Récapitulatif de la classe config:
    1. class Config
    2. {
    3.  public:
    4.    Config();
    5.    void lireConfig();
    6.    ...
    7.  private:
    8.    std::string m_dossierDesign;
    9.    std::string m_langueJeu;
    10.    Design m_design;
    11.    Langue m_langue;
    12.    ...
    13. };

    Mon probleme est:
    Comment intégrer cette fonction permettant de lire ce fichier sachant que les deux objets doivent être initialisés dans la liste d'initialisation?

    Merci d'avance
    • Partager sur Facebook
    • Partager sur Twitter
      29 mars 2008 à 17:59:10

      Il y a plusieurs façons.
      L'une est que la config soit chargée dans son constructeur(!), et qu'elle soit déclarée _avant_ "m_langue" dans la classe qui englobe tout le monde.

      Sinon, tu peux rajouter des indirections avec diverses classes.

      Tu peux aussi ne pas fournir de membre langue dans ta classe, mais un accesseurs qui renvoie la langue contenue dans la config. C'est aussi ça le principe des accesseurs : décorréler propriétés et attributs membres.
      • Partager sur Facebook
      • Partager sur Twitter
      C++: Blog|FAQ C++ dvpz|FAQ fclc++|FAQ Comeau|FAQ C++lite|FAQ BS| Bons livres sur le C++| PS: Je ne réponds pas aux questions techniques par MP.
        30 mars 2008 à 10:53:36

        Citation : lmghs

        Il y a plusieurs façons.
        L'une est que la config soit chargée dans son constructeur(!), et qu'elle soit déclarée _avant_ "m_langue" dans la classe qui englobe tout le monde.


        Qu'est-ce que tu entends par là?
        J'ai une classe à laquelle appartient la classe Config qui s'occupe de la gestion de la configuration et notamment de la langue et du design.

        Citation : lmghs


        Sinon, tu peux rajouter des indirections avec diverses classes.


        Tu veux dire des ponteurs de classes? o_O

        Citation : lmghs


        Tu peux aussi ne pas fournir de membre langue dans ta classe, mais un accesseurs qui renvoie la langue contenue dans la config. C'est aussi ça le principe des accesseurs : décorréler propriétés et attributs membres.



        Autrement dit: fusionner les classes Design, Langue et Config?
        Je trouvais plus clair de fractionner tout ça...


        Désolé, mais je n'ai probablement pas tout compris à ce que tu me disait :D

        EDIT:
        En gros, j'aimerais savoir s'il est possible de faire un truc du genre:
        1. Config::Config() : lireConfig(), m_design(m_dossierDesign), m_langue(m_langueJeu)...
        2. {
        3. }


        même si je sais que le compilateur considère lireConfig comme une variable que je veux définir.
        Alors j'ai essayé:
        1. Config::Config() : m_configLue(lireConfig()), m_design(m_dossierDesign), m_langue(m_langueJeu)...
        2. {
        3. }

        où m_configLue est un bool. J'ai, bien entendu changé le type de retour de lireConfig() en bool.
        Il n'y a pas d'erreur de compilation mais lorsque je fais un
        1. cout << "test lireConfig()" << endl;

        rien ne s'affiche dans la console (je suis sous linux et je lance le programme depuis la console).


        EDIT²:Sinon, il faudrait supprimer la liste d'initialisation et surcharger l'opérateur = des classes Design et Langue pour lancer la fonction lireConfig dans le corps de la méthode d'initialisation et ensuite faire:
        1. m_design = m_dossierDesign;
        2. m_langue = m_langueJeu;



        EDIT3: :-°
        J'ai essayé de surcharger l'opérateur =, mais j'ai encore une erreur de segmentation lors de l'execution du programme. Avec des cout, j'ai réussi à déterminer que l'erreur venait d'un accesseur dans la classe Design depuis une autre classe et plus précisément lors de l'appel de l'attribut std::string m_cheminDesign;
        Après un cout dessus, je me suis aperçu qu'il y avait une légère fuite de mémoire, qui, a mon avis est due au fait que la chaine n'a pas été initialisée, ce qui est pourtant le cas, ou qui aurait été le cas si la méthode operator= avait été appellée.

        Mais, après quelques couts, je me suis aperçu que c'était tout le constructeur de ma classe Config qui n'était pas executé.
        En remontant encore, j'arrive à ma classe mère, Echiquier (je fais un jeu d'échecs), dont voici le constructeur:
        1. //Initialisation de l'echiquier
        2. Echiquier::Echiquier() : e_configuration(),
        3.    e_ecran(e_configuration, e_cases, e_pieceTouchee),
        4.    e_feuillePartie(),
        5.    e_bloque(true),
        6.    e_auxBlancs(true)
        7. {
        8. }

        et, dans le echiquier.h:
        1. class Echiquier
        2. {
        3.  public:
        4.    Echiquier();//Initialisation de l'echiquier
        5. ...
        6.  protected:
        7.    std::string e_cases[64];//Cases contenant les pièces, par exemple pb = pion blanc
        8.    Fenetre e_ecran;//la fenetre
        9.    Coordonnees e_pieceTouchee;//La piece qu'on a dans la main
        10.    Config e_configuration;//La configuration du jeu(langue, design,...)
        11.    Partie e_feuillePartie;//La feuille de partie
        12.    bool e_bloque;//Si true, l'echiquier est bloqué
        13.    bool e_auxBlancs;//Si true, aux blancs de jouer
        14. };


        En fait, j'ai beaucoup de classes imbriquées entre elles :D
        dans le constructeur de la classe Fenetre, il y a un appel à la classe Config pour avoir les images du design
        C'est cette méthode appellée qui fait tout planter.
        Pourtant, si on suit la logique, la configuration devrait être lancée avant...
        • Partager sur Facebook
        • Partager sur Twitter
          30 mars 2008 à 22:48:24

          Tes classes ne m'ont pas l'air de rentrer dans la catégorie des classes pour lesquelles la copie signifie quelque chose de pertinent, interdis là plutôt.

          Pour en revenir à la question initiale, plusieurs façons donc:
          (1)
          1. struct QuiEnglobe : boost::noncopyable
          2. {
          3.    QuiEnglobe(std::string const& fichier_conf)
          4.    : m_langue(m_config.langue())
          5.    , m_config(fichier_conf)
          6.    {}
          7. private:
          8.    Config m_config;
          9.    Langue /*const&*/ m_langue;
          10. };


          Ceci marche, malgré l'inversion volontaire (qui fera râler plus d'un compilo à juste titre). L'ordre de construction des variables membre respecte l'ordre de déclaration des membres dans la définition de la classe. Donc m_config sera construite avant m_langue (même si la liste d'initialisation dit le contraire!). Ce qui permet d'utiliser m_config pour les constructions des autres membres.

          (3) Priopriété != variable membre
          Voilà la mise en pratique d'une règle trop souvent bafouée: on n'est pas obligé de fournir un couple d'accesseur/mutateur pour chaque variable membre d'une classe et vice-versa.

          1. struct QuiEnglobe : boost::noncopyable
          2. {
          3.    QuiEnglobe(std::string const& fichier_conf)
          4.    : m_config(fichier_conf)
          5.    {}
          6.    Langue const& langue() const { return m_config.langue(); }
          7. private:
          8.    Config m_config;
          9. };




          Et il y a plein d'autres façons de tout organiser, mais cela demande d'avoir du recul par rapport à ce que l'on cherche à modéliser.
          • Partager sur Facebook
          • Partager sur Twitter
          C++: Blog|FAQ C++ dvpz|FAQ fclc++|FAQ Comeau|FAQ C++lite|FAQ BS| Bons livres sur le C++| PS: Je ne réponds pas aux questions techniques par MP.
            31 mars 2008 à 18:15:01

            Citation : lmghs


            Pour en revenir à la question initiale, plusieurs façons donc:
            (1)

            1. struct QuiEnglobe : boost::noncopyable
            2. {
            3.    QuiEnglobe(std::string const& fichier_conf)
            4.    : m_langue(m_config.langue())
            5.    , m_config(fichier_conf)
            6.    {}
            7. private:
            8.    Config m_config;
            9.    Langue /*const&*/ m_langue;
            10. };


            Ceci marche, malgré l'inversion volontaire (qui fera râler plus d'un compilo à juste titre). L'ordre de construction des variables membre respecte l'ordre de déclaration des membres dans la définition de la classe. Donc m_config sera construite avant m_langue (même si la liste d'initialisation dit le contraire!). Ce qui permet d'utiliser m_config pour les constructions des autres membres.


            J'avoue ne pas avoir tout compris:
            Autrement dit, l'ordre de la liste d'initialisation importe peu, c'est l'ordre de déclaration des variables membres qui compte?

            Citation : lmghs


            (3) Priopriété != variable membre
            Voilà la mise en pratique d'une règle trop souvent bafouée: on n'est pas obligé de fournir un couple d'accesseur/mutateur pour chaque variable membre d'une classe et vice-versa.


            Citation : lmghs

            1. struct QuiEnglobe : boost::noncopyable
            2. {
            3.    QuiEnglobe(std::string const& fichier_conf)
            4.    : m_config(fichier_conf)
            5.    {}
            6.    Langue const& langue() const { return m_config.langue(); }
            7. private:
            8.    Config m_config;
            9. };

            Là j'ai pas compris, on a le droit de mettre des fonction dans des structures?
            Et qu'est-ce que boost::noncopyable ?

            Merci :D, je vais essayer quelques trucs.
            • Partager sur Facebook
            • Partager sur Twitter
            Anonyme
              31 mars 2008 à 18:27:01

              Il y a struct en C et struct en C++. http://www.siteduzero.com/forum-83-175473-2086015-les-mots-clefs.html#r2086015
              voir aussi http://www.siteduzero.com/forum-83-175473-1885791-les-mots-clefs.html#r1885791

              boost::noncopyable est, comme sont l'indique, une classe non copiable.
              Son code doit ressembler à qqch comme :
              1. class noncopyable {
              2. // On est en private par défaut.
              3. noncopyable(const noncopyable&) { /* Rien à faire. */ }
              4. noncopyable& operator=(const noncopyable&) { /* Rien à faire. */ }
              5. };

              Ainsi en héritant (en public, protected, ou private, ça ne change rien) on empêche la copie.

              Citation : Toi

              Autrement dit, l'ordre de la liste d'initialisation importe peu, c'est l'ordre de déclaration des variables membres qui compte?

              L'un importe l'autre. Le résultat sera le même si tu modifies la déclaration de la classe ou la liste d'initialisation. Mais c'est sûr que modifier la liste d'initialisation est plus clair si il y a un ordre logique dans la déclaration des attributs dans la définition de la classe.
              • Partager sur Facebook
              • Partager sur Twitter
                31 mars 2008 à 20:11:27

                Ok, merci à tous les deux!
                Je ne savais pas pour les "struct".
                J'ai enfin résolu mon problème, c'était une addition de bugs en fait :D

                Encore merci et à bientôt !
                • Partager sur Facebook
                • Partager sur Twitter
                  31 mars 2008 à 20:16:25

                  (1) C'est bien ça!
                  (3) En gros, struct == class où tout est public par défaut.
                  • Partager sur Facebook
                  • Partager sur Twitter
                  C++: Blog|FAQ C++ dvpz|FAQ fclc++|FAQ Comeau|FAQ C++lite|FAQ BS| Bons livres sur le C++| PS: Je ne réponds pas aux questions techniques par MP.

                  Constructeur et fonctions

                  × 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