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 :

Accesseur d'une variable membre (setter)


Sujet :

C++

  1. #1
    Membre confirmé Avatar de LinuxUser
    Inscrit en
    Avril 2007
    Messages
    857
    Détails du profil
    Informations forums :
    Inscription : Avril 2007
    Messages : 857
    Points : 616
    Points
    616
    Par défaut Accesseur d'une variable membre (setter)
    Bonjour,

    J'ai un problème avec un getter et je ne comprends absolument pas pourquoi.

    Je vais essayer d'exposer la situation.

    Si on a une classe Conteneur par exemple:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    class Conteneur
    {
      private:
        Objet m_obj;
    };
    Un classe Objet qui contient des paramètres:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    class Objet
    {
      private:
        Param m_param;
      public:
        Param& getParam();
    };
    Et donc une classe paramètres:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    class Param
    {
      private:
        double m_p1;
        double m_p2;
        ...
        double m_pN;
     
      public:
        double getP1() const;
        void setP1();
    }
    Maintenant si on ajoute une méthode pour initialiser l'attribut m_obj:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    void Conteneur::initializeObj()
    {
      double p1 = ...;
      double p2 = ...;
      ...
      double pN = ...;
      m_obj.initilizeParam(p1,...,pN);
    }
    Et que dans Object.cpp:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    void Objet::initializeParam(double& p1, double& p2, ..., double& pN)
    {
      m_param = Param(p1, .., pN);
    }
    Param.cpp:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    Param::Param(double& p1, ..., double& pN) : m_p1(p1), ..., m_pN(pN)
    {
    }
    Le problème et le suivant
    * lorque j'initialise les paramètres à travers le constructeur et qu'ensuite on lit ces valeurs (avec un getter, par exemple getP1()) il n'y a pas de problème, la valeur à bien été initialisée
    * par contre, si après l'initilisation je modifie une valeur d'un paramètre (par un setter) et que je lis ensuite la valeurs du paramètre, la valeur renvoyée est celle initialisée par le construteur et non celle modifiée par le setter, exemple:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    void Conteneur::method()
    {
      initializeObj(); // les paramètres sont tous bien initilisés
      std::cout"<<\n p1 = "<<getObj().getParam().getP1(); // par exemple p1 = 1.5 ici
      // si ensuite
      double p1 = 3.14;
      getObj().getParam().setP1(p1); 
      std::cout"<<\n p1 = "<<getObj().getParam().getP1(); // p1 vaut encore 1.5 au lieu de 3.14
    }
    Quand j'affiche la valeur dans le setter de la classe Param, j'ai bien 3.14, mais dès qu'on accède à la valeur par le getter, il renvoie toujours la valeur initialisée dans le constructeur, à savoir 1.5.

    Y a vraiment quelque chose qui m'échappe.

    Merci de votre aide.

  2. #2
    Inactif  


    Homme Profil pro
    Doctorant sécurité informatique — Diplômé master Droit/Économie/Gestion
    Inscrit en
    Décembre 2011
    Messages
    9 012
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 30
    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 012
    Points : 23 209
    Points
    23 209
    Par défaut
    Bonjour,

    Au lieu d'utiliser 50 variables doubles, pourquoi ne pas utiliser un tableau avec un enum (ou un std::array voir un std::vector )?
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    class Foo
    {
          public :
                 enum INDICE{D1, D2, D3, MAX };
                 double & get(INDICE);
                 void set(INDICE, double);
          private :
                 double tab[MAX];
    }
    Pour ta fonction d'initialisation, pourquoi ne pas utiliser un std::initializer_list ? (C++11)

    Sinon, pourrait tu nous donner l'implémentation de ton setter? Voir même un code minimal qu'on puisse compiler ?

  3. #3
    Membre confirmé Avatar de LinuxUser
    Inscrit en
    Avril 2007
    Messages
    857
    Détails du profil
    Informations forums :
    Inscription : Avril 2007
    Messages : 857
    Points : 616
    Points
    616
    Par défaut
    Citation Envoyé par Neckara Voir le message
    Au lieu d'utiliser 50 variables doubles, pourquoi ne pas utiliser un tableau avec un enum (ou un std::array voir un std::vector )?
    Pour simplifier j'ai tout mis en double dans l'exemple, mais y a plusieurs types différents en vrai.

    Citation Envoyé par Neckara Voir le message
    Pour ta fonction d'initialisation, pourquoi ne pas utiliser un std::initializer_list ? (C++11)
    Pas C++11 pour l'insatnt, ça doit pouvoir tourner sur des vieux systèmes avec des vieux compilateurs, donc j'évite tout ce qui peut nuire à la compatibilité du portage du code.

    Citation Envoyé par Neckara Voir le message
    Sinon, pourrait tu nous donner l'implémentation de ton setter? Voir même un code minimal qu'on puisse compiler ?
    OK, je prépare ça.

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

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 612
    Points : 30 611
    Points
    30 611
    Par défaut
    Salut,

    Vérifie un peu la signature de ton accesseur (qui est juste au demeurant)!!!:
    Il renvoie une valeur et, qui plus est, c'est une fonction constante.

    S'il s'agissait d'un objet, tu le renverrais (normalement) sous la forme d'une référence constante

    Le mutateur (qu'il vaut mieux éviter, mais on ne va pas relancer un débat qui existe déjà par ailleurs ),doit etre directement appelé depuis ton objet, et non depuis l'accesseur sur la variable que tu essayes de modifier .

    En plus, normalement, le compilateur devrait refuser purement et simplement, vu qu'un double n'a pas de fonction "setXXX"
    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 confirmé Avatar de LinuxUser
    Inscrit en
    Avril 2007
    Messages
    857
    Détails du profil
    Informations forums :
    Inscription : Avril 2007
    Messages : 857
    Points : 616
    Points
    616
    Par défaut
    Citation Envoyé par koala01 Voir le message
    S'il s'agissait d'un objet, tu le renverrais (normalement) sous la forme d'une référence constante
    Je suis bien d'accord avec toi, mais dans mon cas, je veux renvoyer une valeur (pas une référence). Et le const, c'est pour montrer qu'il s'agit d'une lecture seulement, donc pas de modification de la valeur.
    Citation Envoyé par koala01 Voir le message
    Le mutateur (qu'il vaut mieux éviter, mais on ne va pas relancer un débat qui existe déjà par ailleurs ),doit etre directement appelé depuis ton objet, et non depuis l'accesseur sur la variable que tu essayes de modifier .
    Je n'ai pas compris ce que tu as voulu dire.

    Citation Envoyé par koala01 Voir le message
    En plus, normalement, le compilateur devrait refuser purement et simplement, vu qu'un double n'a pas de fonction "setXXX"
    Un setter sur un double c'est plutôt commun:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    void setValue(double newVal);
    Me trompe-je?

  6. #6
    Membre confirmé Avatar de LinuxUser
    Inscrit en
    Avril 2007
    Messages
    857
    Détails du profil
    Informations forums :
    Inscription : Avril 2007
    Messages : 857
    Points : 616
    Points
    616
    Par défaut
    J'ai mis en pièce jointe, une archive contenant un exemple compilable (le makefile est fourni).
    Désolé j'ai pas eu le temps de changer les noms des classes.
    Fichiers attachés Fichiers attachés

  7. #7
    r0d
    r0d est déconnecté
    Expert éminent

    Homme Profil pro
    tech lead c++ linux
    Inscrit en
    Août 2004
    Messages
    4 262
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Ain (Rhône Alpes)

    Informations professionnelles :
    Activité : tech lead c++ linux

    Informations forums :
    Inscription : Août 2004
    Messages : 4 262
    Points : 6 680
    Points
    6 680
    Billets dans le blog
    2
    Par défaut
    Citation Envoyé par LinuxUser Voir le message
    Quand j'affiche la valeur dans le setter de la classe Param, j'ai bien 3.14, mais dès qu'on accède à la valeur par le getter, il renvoie toujours la valeur initialisée dans le constructeur, à savoir 1.5.
    A vue de nez, il est probable que le getParam te renvoie une copie du param. Donc:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    getObj().getParam().setP1(p1);
    ça va modifier la valeur de p1 sur une copie de param, et non sur l'instance de param que tu veux modifier. Si c'est bien ça, il faut de getParam renvoie une référence sur le param "membre", et pas une copie.
    « L'effort par lequel toute chose tend à persévérer dans son être n'est rien de plus que l'essence actuelle de cette chose. »
    Spinoza — Éthique III, Proposition VII

  8. #8
    r0d
    r0d est déconnecté
    Expert éminent

    Homme Profil pro
    tech lead c++ linux
    Inscrit en
    Août 2004
    Messages
    4 262
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Ain (Rhône Alpes)

    Informations professionnelles :
    Activité : tech lead c++ linux

    Informations forums :
    Inscription : Août 2004
    Messages : 4 262
    Points : 6 680
    Points
    6 680
    Billets dans le blog
    2
    Par défaut
    Effectivement, quand tu fais:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    WS18 ModelHandler::getRheologyWS18()
    {
    	return (m_rheologyWS18);
    }
    ce qui est retourné par la fonction est une copie de m_rheologyWS18.
    Il faut renvoyer une référence.

    Ou alors, la fonction ne devrait pas s'appeler getRheologyWS18, mais getRheologyWS18Copy, ou quelques chose comme ça.

    Hope it helps.
    « L'effort par lequel toute chose tend à persévérer dans son être n'est rien de plus que l'essence actuelle de cette chose. »
    Spinoza — Éthique III, Proposition VII

  9. #9
    Membre confirmé Avatar de LinuxUser
    Inscrit en
    Avril 2007
    Messages
    857
    Détails du profil
    Informations forums :
    Inscription : Avril 2007
    Messages : 857
    Points : 616
    Points
    616
    Par défaut
    Oh mais quel con je suis

    Je voulais effectivement renvoyer la réference et non une copie.

    Merci infiniment à vous.

  10. #10
    r0d
    r0d est déconnecté
    Expert éminent

    Homme Profil pro
    tech lead c++ linux
    Inscrit en
    Août 2004
    Messages
    4 262
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Ain (Rhône Alpes)

    Informations professionnelles :
    Activité : tech lead c++ linux

    Informations forums :
    Inscription : Août 2004
    Messages : 4 262
    Points : 6 680
    Points
    6 680
    Billets dans le blog
    2
    Par défaut
    <mode Maître Capello>
    assesseur, nom masculin
    Sens 1 : Magistrat adjoint au juge [Droit].
    Sens 2 : Personne qui assiste, seconde une autre dans ses fonctions. adjoint
    </mode>

    Tu voulais dire "accesseur" je suppose
    « L'effort par lequel toute chose tend à persévérer dans son être n'est rien de plus que l'essence actuelle de cette chose. »
    Spinoza — Éthique III, Proposition VII

  11. #11
    Membre confirmé Avatar de LinuxUser
    Inscrit en
    Avril 2007
    Messages
    857
    Détails du profil
    Informations forums :
    Inscription : Avril 2007
    Messages : 857
    Points : 616
    Points
    616
    Par défaut
    Oui en effet.

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

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 612
    Points : 30 611
    Points
    30 611
    Par défaut
    Citation Envoyé par LinuxUser Voir le message
    Je n'ai pas compris ce que tu as voulu dire.

    Un setter sur un double c'est plutôt commun:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    void setValue(double newVal);
    Au temps pour moi...

    J'avais confondu
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    getObj().getParam().setP1(p1);
    avec
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    param.getP1(1).setP1(valeur);


    Ceci dit, la présence d'un mutateur ou (pire) d'un accesseur non constant est souvent signe du fait que ton membre aurait, largement, intérêt à être simplement public.

    Si tu regardes attentivement les composants de la STL:
    • il n'y a aucun accesseur ou (pire) aucun mutateur "simple"
    • Si une référence (constante ou non) sur un membre de la collection est renvoyée, c'est par la fonction at, ou par l'opérateur [], qui a une sémantique particulière (et qui font tout deux bien plus qu'un simple getXXX )
    • Les éléments (constants ou non) sont encapsulé dans une structure intermédiaire pour toutes les autres fonction : l'itérateur, qui permet de parcourir la collection de manière correcte
    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

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

Discussions similaires

  1. Acceder à une variable membre
    Par buzzkaido dans le forum C++
    Réponses: 8
    Dernier message: 29/10/2007, 18h40
  2. Réponses: 8
    Dernier message: 21/06/2007, 14h49
  3. Réponses: 6
    Dernier message: 02/06/2007, 02h07
  4. Réponses: 7
    Dernier message: 28/10/2006, 20h07
  5. comment récupérer une variable membre?
    Par marute dans le forum MFC
    Réponses: 4
    Dernier message: 13/04/2006, 17h11

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