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 :

const et surcharge operateur via fct membre


Sujet :

Langage C++

  1. #1
    Membre éclairé Avatar de mensoif
    Profil pro
    Inscrit en
    Mai 2008
    Messages
    248
    Détails du profil
    Informations personnelles :
    Âge : 36
    Localisation : France

    Informations forums :
    Inscription : Mai 2008
    Messages : 248
    Par défaut const et surcharge operateur via fct membre
    Bonsoir,

    je suis en train d'implémenter un avl arbre.

    J'ai donc ma classe avl générique qui fonctionne lorsque j'instancie avec un int par exemple.

    Mon but est de l'instancier avec des Segment (classe perso)
    Un segment étant composé de 2 Points (autre classe perso)

    hélas, je me choppe une erreur que j'ai dus mal à résoudre:

    erreur: passing ‘const Segment’ as ‘this’ argument of ‘bool Segment::operator<(const Segment&)’ discards qualifiers
    qui m'amène à d'autre erreur (instantiated from here etc.)


    J'ai donc vérifier dans la faq en ce qui concernait les surcharges, et hormi une distinction entre la surchage d'operateur via fonction membre ou fonction libre je n'ai rien trouvé.


    Voici la surcharge de l'opéarteur < dans ma classe segment et dans ma classe Point

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    bool Segment::operator<(const Segment &s) {
    	// recherche du endpoint gauche
    	if(m_a.getType() == 0) 
    		return (m_a < s.getA());
    	else 
    		return (m_b < s.getB());
     
    }
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
     
    bool Point::operator<(const Point &p2) {
    	if(m_x < p2.getX())
    		return true; 
    	if(m_x > p2.getX())
    		return false;
     
    	// comparaison par Y
    	if(m_y < p2.getY())
    		return true;
     
    	return false;
    }
    En vous remerciant par avance

  2. #2
    Membre Expert
    Avatar de Goten
    Profil pro
    Inscrit en
    Juillet 2008
    Messages
    1 580
    Détails du profil
    Informations personnelles :
    Âge : 35
    Localisation : France

    Informations forums :
    Inscription : Juillet 2008
    Messages : 1 580
    Par défaut
    Le message est plutôt clair. Tu essayes de comparer un (ou deux) segments constants avec une méthode non constantes (l'opérateur< ici). Sa peut pas marcher.
    Donc passe l'opérateur < en constant et c'est réglé. (opérateur qui doit de toute façon être constant puisqu'il ne fait aucune modification sur l'état interne de ton objet).

  3. #3
    Membre éclairé Avatar de mensoif
    Profil pro
    Inscrit en
    Mai 2008
    Messages
    248
    Détails du profil
    Informations personnelles :
    Âge : 36
    Localisation : France

    Informations forums :
    Inscription : Mai 2008
    Messages : 248
    Par défaut
    En effet le message est clair, et pourtant j'étais partis dans une direction de recherche totalement opposée ...

    Je te remercie grandement !

  4. #4
    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,

    Les opérateurs de comparaison (<, <=, ==, >, >=) doivent être déclarés comme des fonctions membres constantes, parce qu'ils s'engagent à ... ne pas modifier le premier opérande (ni le second, d'ailleurs) auquel ils se rapportent.

    Il faut savoir qu'il existe un concept que l'on appelle, en anglais, la const correctness, que nous pourrions traduire (à défaut de mieux) par "le respect de la constance (des objets)".

    Ce concept nous fait remarquer qu'il est possible d'invoquer une fonction constante depuis un objet non constant, car, si un objet peut être modifié il peut aussi... ne pas l'être, mais que seules les fonctions constantes (qui se sont explicitement engagées à ne pas modifier l'objet auquel elles se rapportent) peuvent être invoquées depuis... des objets constants car nous courons le risque de voir une fonction qui ne s'est pas engagée à ne pas modifier l'objet avoir pour résultat... de le modifier.

    Pour indiquer au compilateur qu'une fonction membre s'engage à ne pas modifier l'objet au départ duquel elle est invoquée, c'est tout simple: il suffit de faire suivre la parenthèse fermante de la liste de ses arguments du mot clé const

    L'opérateur < de ta classe segment devrait donc être déclaré sous la forme de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    class Segment
    {
        /* tout le reste de la classe */
        public:
            bool operator(Segment const & ) const;
    };
    celui de la classe Point devrait être déclaré sous la forme de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    class Point
    {
        /* tout le reste de la classe */
        public
            bool operator(Point const & ) const;
    };
    Et ils devraient donc être définis sous les formes (respectives) 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
    15
    16
    17
    18
    19
    20
    bool Segment::operator<(const Segment &s) const {
    	// recherche du endpoint gauche
    	if(m_A.getType() == 0) 
    		return (m_a < s.getA());
    	else 
    		return (m_b < s.getB());
     
    } 
    bool Point::operator<(const Point &p2) const{
    	if(m_x < p2.getX())
    		return true; 
    	if(m_x > p2.getX())
    		return false;
     
    	// comparaison par Y
    	if(m_y < p2.getY())
    		return true;
     
    	return false;
    }
    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 éclairé Avatar de mensoif
    Profil pro
    Inscrit en
    Mai 2008
    Messages
    248
    Détails du profil
    Informations personnelles :
    Âge : 36
    Localisation : France

    Informations forums :
    Inscription : Mai 2008
    Messages : 248
    Par défaut
    Merci pour ce rappel détaillé, ça ne fait que du bien.

  6. #6
    Invité
    Invité(e)
    Par défaut
    Bonjour,
    L'explication est très claire, mais mon compilateur (Borland Builder C++)n'a pas réagi de la même façon.
    Il est vrai que mes operator ne passent pas les paramètres par référence (&).
    Le prototype est par exemple
    bool operator|| ( VECTEUR V2 ); // teste si this est parallèle à V2
    Par ailleurs, VECTEUR est une structure et non une classe (avec plusieurs constructeurs)
    Ma question est "Est une faute?", "Pourquoi utiliser le mot clé "const" + "&", ce qui me parait contradictoire".
    Autre hypothèse, mon compilateur est satisfait de la syntaxe puisqu'il s'agit de struct et non class ?

    J'ai bien compris que puisqu'on compare 2 valeurs, celle de gauche (this) et celle de droite V2 le mot-clé const juste après la parenthèse concerne this.

    Cordialement.

  7. #7
    Membre Expert
    Avatar de Joel F
    Homme Profil pro
    Chercheur en informatique
    Inscrit en
    Septembre 2002
    Messages
    918
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 45
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Chercheur en informatique
    Secteur : Service public

    Informations forums :
    Inscription : Septembre 2002
    Messages : 918
    Par défaut
    Citation Envoyé par Pierre Dolez Voir le message
    Bonjour,
    Le prototype est par exemple
    bool operator|| ( VECTEUR V2 ); // teste si this est parallèle à V2
    Par ailleurs, VECTEUR est une structure et non une classe (avec plusieurs constructeurs)
    Tu passes tes arguments par copie ... ce qui est tout sauf optimal ..

  8. #8
    Membre Expert
    Avatar de Goten
    Profil pro
    Inscrit en
    Juillet 2008
    Messages
    1 580
    Détails du profil
    Informations personnelles :
    Âge : 35
    Localisation : France

    Informations forums :
    Inscription : Juillet 2008
    Messages : 1 580
    Par défaut
    bool operator|| ( VECTEUR V2 ); // teste si this est parallèle à V2
    Wow... mauvaise idée.. Utilise plutôt une fonction.


    Par ailleurs, VECTEUR est une structure et non une classe (avec plusieurs constructeurs)
    C'est la même chose, modulo la portée par défaut et le type d'héritage par défaut.

    Ma question est "Est une faute?", "Pourquoi utiliser le mot clé "const" + "&", ce qui me parait contradictoire".
    Parce que la référence évite la copie mais permet de modifier la source, ce qu'on empêche en la rendant constante.

  9. #9
    Invité
    Invité(e)
    Par défaut
    Oui, il est vrai que pour la surcharge des opérateurs, probablement que je n'ai pas réussi autrement à l'époque.
    Par ailleurs, il m'arrive très souvent de passer du TPointLong en copie.
    TPointLong est une structure qui contient 2 long
    Auriez-vous un petit lien avec une petite explication et un petit exemple?
    Je vais peut-être revoir ma façon de traiter cela.
    Merci.

  10. #10
    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
    Citation Envoyé par Pierre Dolez Voir le message
    Bonjour,
    L'explication est très claire, mais mon compilateur (Borland Builder C++)n'a pas réagi de la même façon.
    Il est vrai que mes operator ne passent pas les paramètres par référence (&).
    Ouhhh... pas bien, ca
    Le prototype est par exemple
    bool operator|| ( VECTEUR V2 ); // teste si this est parallèle à V2
    Par ailleurs, VECTEUR est une structure et non une classe (avec plusieurs constructeurs)
    Classes et structures, même combat ...

    En C++ il n'y a qu'une différence entre une classe et une structure: la visibilité par défaut de ses membres
    Ma question est "Est une faute?",
    C'est, certes, autaorisé, mais ce n'est pas recommandé... surtout si l'objet passé prend du temps ou demande beaucoup de ressource lors de la copie.

    Lorsque tu passe un paramètre par valeur, il y a copie, ce qui fait que rien de ce que tu pourrais faire dans la fonction appelée ne sera répercuté dans la fonction appelante.

    Seulement, s'il est assez rapide (et que cela ne demande pas énormément de ressources) de copier une variable de type primitif (char, short, int, long, float, double), il est souvent beaucoup plus lent, et cela demande souvent beaucoup de ressources, de copier... une structure ou une classe.

    De plus, il y a certains cas dans lesquels on rend la classe... non copiable, principalement parce qu'elle entre dans une hiérarchie polymorphe.

    Bref, comme tu peux le remarquer, il y a un tas de raisons qui font qu'il est préférable de ne pas passer une classe ou une structure par valeur
    "Pourquoi utiliser le mot clé "const" + "&", ce qui me parait contradictoire".
    Où vois tu une contradiction

    Une référence agit, au final, exactement comme un pointeur, si ce n'est que tu as une garantie de non nullité, et que l'on ne peut pas changer d'objet référencé une fois que la référence a été définie.

    Le mot clé const, quant à lui, indique simplement que tu t'engage à ne pas essayer de modifier l'objet déclaré constant

    La référence constante a enfin cet avantage de permettre la création de ce que l'on appelle une "variable temporaire anonyme":il est possible de créer une variable qui n'existera que pour la durée de l'exécution de la fonction appelée, pour autant que la classe ou la structure dispose d'un constructeur susceptible d'agir comme opérateur de conversion.

    Par exemple, il existe un constructeur pour la classe string qui prend... un pointeur sur une chaine de caractères C style.
    Si tu dispose d'une fonction foo prenant une référence constante sur une std::string proche de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    void foo(std::string const & str)
    {
        /*... bla bla bla ...*/
    }
    tu peux envisager d'utiliser au choix une variable existante:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    int main()
    {
        std::string str;
        /* on modifie la valeur de str */
        foo(str);
        return 0;
    }
    mais tu peux aussi envisager d'utiliser quelque chose proche de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    int main()
    {
        foo("salut le monde"); /* création d'une variable anonyme contenant 
                                * "salut le monde"
                                */
    }
    Autre hypothèse, mon compilateur est satisfait de la syntaxe puisqu'il s'agit de struct et non class ?
    Voilà bien une drôle d'hypothèse...

    Hé non, l'utilisation d'une structure au lieu d'une classe n'a rien à voir dans la choucroute

    La raison est, tout simplement, que tu passe ton vecteur par valeur et non par référence, avec tous les inconvénients déjà cités
    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

  11. #11
    Invité
    Invité(e)
    Par défaut
    Merci Koala01, je vais revoir sérieusement tout ça.
    Mais il est possible que je ne me sois pas trop posé la question parce que, à part VECTEUR et TPolntLong, je n'ai normalement que des pointeurs sur des classes, mais j'ai compris et je ne peux pas laisser ça.
    Merci.

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

Discussions similaires

  1. Surcharge operateur () et const
    Par zenux dans le forum Débuter
    Réponses: 5
    Dernier message: 28/05/2012, 11h18
  2. surcharge operateur avec "const"
    Par Krishna dans le forum C++
    Réponses: 6
    Dernier message: 18/04/2008, 09h32
  3. [debutante] surcharge operateur <<
    Par norkius dans le forum Débuter
    Réponses: 3
    Dernier message: 24/10/2005, 12h20
  4. [Surcharge]Operateur<< avec une classe maison
    Par KeNnEdY dans le forum C++
    Réponses: 6
    Dernier message: 14/09/2005, 15h51
  5. surcharge operateur && pointeurs
    Par le y@m's dans le forum C++
    Réponses: 6
    Dernier message: 10/05/2005, 15h57

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