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 :

renvoyer une instance d'un membre d'une classe


Sujet :

C++

  1. #1
    Membre habitué Avatar de touftouf57
    Profil pro
    Développeur .NET
    Inscrit en
    Décembre 2007
    Messages
    362
    Détails du profil
    Informations personnelles :
    Âge : 45
    Localisation : France, Moselle (Lorraine)

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

    Informations forums :
    Inscription : Décembre 2007
    Messages : 362
    Points : 174
    Points
    174
    Par défaut renvoyer une instance d'un membre d'une classe
    Bonjour à tous

    Je voudrais savoir comment faire pour intégrer complètement dans une Classe, une donnée membre sans passer par un pointeur.
    Je me pose, donc, la question de savoir comment je peux faire ça:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    //Dans le main
    o.getPoint().setX(i);
    avec o qui est une instance de la classe Objet que voici

    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
    public:
    	Objet();
            Objet(char c, int x, int y);
    	Objet(const Objet& obj);
    	Objet(const Point& point);
    	Objet(char c, Point& p);
    	virtual ~Objet();
     
    	virtual void afficher() const;
    	Point getPoint() const;
    	........
     
    private:
    	Point _point;
    	char _car;
    voici le getter de Point:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    Point Objet::getPoint()const{
    	return _point;
    }
    De cette façon je perd l'objet Point à la sortie du getter.

    J'ai bien essayé la signature
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    Point& Objet::getPoint()const;
    Mais sans succès. "error C2440: 'return' : impossible de convertir de 'const Point' en 'Point &''"

    Ma première question est elle faisable? Et comment?

    Merci à tous

  2. #2
    Membre régulier
    Inscrit en
    Juillet 2009
    Messages
    96
    Détails du profil
    Informations forums :
    Inscription : Juillet 2009
    Messages : 96
    Points : 85
    Points
    85
    Par défaut
    Je crois que tu n'as malheureusement pas le choix d'utiliser autre chose q'un pointeur. Si tu veux changer une valeur il te faut un pointeur. (Pas pour lire une valeur par contre).

  3. #3
    Inactif  


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

    Informations professionnelles :
    Secteur : Santé

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

    setPoint() -> fonction const dans ton code
    setX(i) -> fonction non const dans ton code
    = incompatible !

    Si tu veux modifier une référence, il ne faut pas renvoyer un const :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    class Object
    {
    public:
       Point& getPoint() { return p; }
    private:
       Point p;
    };
     
    o.getPoint().setX(i); // ok
    Souvent, on fournit les 2 versions (const et non const) pour permettre au compilateur d'optimiser :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    class Object
    {
    public:
       Point& getPoint() { return p; }
       const Point& getPoint() const { return p; }
    private:
       Point p;
    };
     
    cout << o.getPoint(); // appel de la version const
    o.getPoint().setX(i); // appel de la version non const

  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
    Salut,

    Déjà, ton getPoint est, comme l'a signalé gbdivers, une fonction constante, ce qui signifie qu'elle s'engage à ne pas modifier l'objet au départ duquel elle est invoquée.

    De plus, tu renvoie le point par valeur (non constante), ce qui:
    1- implique que, même si tu pouvais le modifier, tu ne modifierais pas l'instance de Object, vu que tu renvoie une copie du point, et que la modification ne sera pas répercutée.
    2- Vu que la fonction est déclarée constante, le compilateur estime que tu travail avec... une instance constante de Object, et donc, que _p est également constant, vu que tu n'a pas dit que cela ne devait pas être le cas. C'est la raison pour laquelle le compilateur t'envoie paitre: on peut sans problème rendre un objet non constant constant, mais on doit indiquer explicitement le fait que l'on veuille faire l'inverse (avec le const_cast )

    Voilà pour les explications quant à ton problème

    Maintenant, je vais, si tu le permet (et même si tu ne le permet pas, d'ailleurs... je m'en fout: j'aurai fini quand tu lira mon message ) aborder le problème de conception que je décèle dans ce que tu fais.

    En effet, il existe la loi dite Demeter qui conseille de faire en sorte qu'un objet n'expose pas plus que le nécessaire.

    Or, le membre de type point est, typiquement un "détail d'implémentation" de la classe Object.

    Je veux dire par là que, à l'extrême limite, l'utilisateur se fout parfaitement du fait que la classe Object utilise en interne la classe (ou la structure) Point:

    Ce qui lui importe, c'est d'être en mesure de positionner son objet. Maintenant, si, au lieu de déclarer un membre de type Point, tu décidais d'utiliser un "simple" tableau de deux éléments ( int pos_[2]) ou carrément deux membres différents (int posX_; int posY_; ), cela ne devrait pas modifier la manière dont l'utilisateur manipule ses instances d'Object

    Par contre ce qui serait surement intéressant de prévoir, c'est un service fourni par la classe Object qui permette d'en déplacer les instances, soit sur base de coordonnées "absolues" (rejoint le point situé en X=truc et en Y=machin) soit sur base d'une distance relative à la position actuelle (déplace toi de (+/-) truc sur l'axe des x et de (+/-) machin sur l'axe des y).

    De même, ce n'est pas le point lui-même qui t'intéresse lorsque tu manipule une instance de Object, c'est... sa position sur l'axe des x et/ ou sa position sur l'axe des y, de manière, par exemple, à comparer cette (ces) position(s) avec celle(s) d'un (ou de plusieurs) autre(s) objet(s) .

    Libre à toi, si le besoin s'en fait sentir, de décider de créer un nouveau point sur base de ces coordonnées, mais, à la base, rien ne te dit que ce sera effectivement nécessaire .

    En outre, le point est, typiquement, une classe que l'on devrait considérer comme immuable: une fois que les coordonnées sont définies, il n'y a aucune raison de décider de les modifier, car, si on le fait, on obtient, tout simplement, un autre point.

    Il ne faut donc pas essayer de réaffecter la coordonnée X ou Y d'un point (la classe Point ne devrait d'ailleurs absolument pas présenter, toujours selon la loi Demeter, de mutateur ("setters"), mais c'est carrément l'ensemble du point qu'il s'agit de réaffecter.

    Tu n'aurais donc pas
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    void Object::foo(int x, int y)
    {
    p_.setX(x);
    p_.setY(y);
    }
    mais plutôt quelque chose comme
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    void Object::bar(int x, int y)
    {
        p_=Point(x,y);
    }
    voir
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    void Object::bar(Point const & dest)
    {
        p_=dest;
    }
    Pour que tu puisse comprendre mon approche, voici les règles que j'essaie de suivre "aussi souvent que possible":
    Un accesseur ("getter") est souvent inutile, à moins qu'il ne représente une propriété intrinsèque de l'objet (getX() pour un point représente la propriété "capable de fournir la position sur l'axe des X, et est donc typiquement une propriété intrinsèque de l'objet, au même titre que le nom pour une personne )
    Le mutateur ne doit être envisagé que si:
    1- si tu as déjà prévu un accesseur
    2- si tu peux décemment envisager le fait que tu garde le même objet lorsque tu modifie le membre
    3- s'il n'existe aucun service rendu par l'objet qui vient modifier le membre "en interne"

    Enfin, lorsqu'un objet devient membre d'une autre classe, il n'est souvent que détail d'implémentation, et ce qui importe à l'utilisateur de l'autre classe est, généralement, seulement une partie des propriétés intrinsèques de l'objet.

    La discussion sur cette manière d'envisager les choses est, bien évidemment ouverte .
    Citation Envoyé par Simonake Voir le message
    Je crois que tu n'as malheureusement pas le choix d'utiliser autre chose q'un pointeur. Si tu veux changer une valeur il te faut un pointeur. (Pas pour lire une valeur par contre).
    On ne le répètera jamais assez: il ne faut utiliser les pointeurs que lorsque l'on n'a vraiment pas le choix.

    Ici, il se fait que l'on a le choix, car la position existera forcément tant que l'objet existe.

    Il est donc clairement préférable d'envisager le recours aux références, et non aux pointeurs
    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. Obtenir une instance d'un objet depuis une dll
    Par blazed dans le forum Langage
    Réponses: 6
    Dernier message: 07/01/2013, 22h28
  2. Réponses: 3
    Dernier message: 13/10/2009, 12h32
  3. Réponses: 3
    Dernier message: 06/10/2009, 13h37
  4. Réponses: 3
    Dernier message: 16/04/2009, 12h00
  5. [Débutant] Créer une instance avec le nom d'une classe
    Par Quetzalcoatl dans le forum Langage
    Réponses: 7
    Dernier message: 23/01/2006, 20h43

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