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 :

l'operateur = entre les classes


Sujet :

C++

  1. #1
    Inactif
    Inscrit en
    Avril 2009
    Messages
    55
    Détails du profil
    Informations forums :
    Inscription : Avril 2009
    Messages : 55
    Points : 44
    Points
    44
    Par défaut l'operateur = entre les classes
    bonjours

    je définir un operateur = entre classes
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    classe Point{
     
    Point operator = (Point & P) {return P;}
    }
    mais ça se passe avec mon compilateur!!!

  2. #2
    Expert éminent sénior
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 369
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France

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

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 369
    Points : 41 518
    Points
    41 518
    Par défaut
    "ça se passe avec mon compilateur" ne définit par correctement ton problème.

    De plus, ce code est très faux pour un opérateur = de classe. L'idiome Copy-And-Swap est préconisé.
    SVP, pas de questions techniques par MP. Surtout si je ne vous ai jamais parlé avant.

    "Aw, come on, who would be so stupid as to insert a cast to make an error go away without actually fixing the error?"
    Apparently everyone.
    -- Raymond Chen.
    Traduction obligatoire: "Oh, voyons, qui serait assez stupide pour mettre un cast pour faire disparaitre un message d'erreur sans vraiment corriger l'erreur?" - Apparemment, tout le monde. -- Raymond Chen.

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

    Il est déjà beaucoup plus facile de comprendre ce que fait "operator =" lorsque l'on essaye de l'exprimer en bon francais: il s'agit de "l'opératteur d'affectation"

    Une fois cette expression faite, tu devrais presque être en mesure, au prix d'un peu de réflexion, de déterminer la manière correcte de le déclarer .

    Tu peux aussi décider de retenir la manière de le déclarer par coeur, mais, il faut avouer que cela a beaucoup moins de charme

    Allons y donc une fois pour la réflexion, car elle car elle est vraiment intéressante

    Nous savons donc qu'il s'agit d'un opérateur d'affectation. Essayons de définir clairement chacun des terme:
    • opérateur: pour faire simple, nous pouvons dire qu'il s'agit d'une fonction, même si elle réagit de manière un peu particulière
    • affectation: c'est le fait de donner à l'instance courante d'un objet le contenu d'une instance différente

    Le fait de parler d'instance courante signifie que nous devons renvoyer... une référence sur un objet, et que l'objet renvoyé doit venir de this.

    Pour mémoire, car, pour l'instant nous ne nous inquiétons de la manière correcte de déclarer l'opérateur, cela signifie aussi, étant donné que this est un pointeur qu'il faudra au final renvoyer... ce qui est pointé par this

    Il faut aussi s'intéresser à "l'instance différente" que nous voulons assigner à l'instance courante... Elle doit:
    1. Ne pas être copiée lorsqu'elle est passée comme paramètre à l'opérateur
    2. Ne pas pouvoir être modifiée par la fonction pour respecter le sacro-saint principe de "const-correctness"

    Le (1) implique que l'argument doit être transmis... par référence.

    Le (2) implique que l'argument doit être... constant.

    au final, nous nous rendons donc compte que l'opérateur d'assignation, que nous désignerons sous le nom de operator= doit renvoyer une référence sur l'objet courent (MonType&) et prendre en argument une référence constante sur l'objet à assigné (MonType const & )

    La déclaration correcte sera donc de l'ordre de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    MonType& operator = (MonType const & );
    Maintenant que la réflexion est faite, tu peux le retenir par coeur
    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

  4. #4
    Expert confirmé
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Décembre 2003
    Messages
    3 549
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Essonne (Île de France)

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

    Informations forums :
    Inscription : Décembre 2003
    Messages : 3 549
    Points : 4 625
    Points
    4 625
    Par défaut
    Il est souvent plus intéressant d'écrire
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    MonType& operator = (MonType);
    en fait.
    Boost ftw

  5. #5
    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
    Points : 13 017
    Points
    13 017
    Par défaut
    Pour rappel, la FAQ contient déjà ce genre de réponse.
    Merci de la consulter.

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

    Informations forums :
    Inscription : Juillet 2008
    Messages : 1 580
    Points : 2 205
    Points
    2 205
    Par défaut
    Citation Envoyé par loufoque Voir le message
    Il est souvent plus intéressant d'écrire
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    MonType& operator = (MonType);
    en fait.
    Par contre derrière on a toujours l'idiome Copy'n'Swap ?
    "Hardcoded types are to generic code what magic constants are to regular code." --A. Alexandrescu

  7. #7
    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 Goten Voir le message
    Par contre derrière on a toujours l'idiome Copy'n'Swap ?
    En fait, c'est, justement parce que l'on décide de passer l'argument par valeur plutôt que par référence qu'une copie de l'objet passé s'effectue...

    Il n'y a donc normalement plus qu'à swapper le contenu de l'argument et de l'objet courant

    Or, quand on y regarde de plus près, c'est effectivement ce que conseille l'idiome copy and swap: créer une copie de l'objet passé en paramètre et inverser le contenu de cette copie avec l'objet courant

    Il y a peut être des raisons qui font qu'il est plus intéressant de directement demander la copie (louffoque, pourrais tu les donner, s'il y en a), mais, personnellement, j'aime autant "garder la main" sur le moment où je fais des copies de mes objets, et je trouve - à titre personnel - plus cohérent de rester sur le principe d'éviter les copies de classes autant que faire se peut...

    Ne serait-ce que parce qu'il reste possible que le constructeur par copie lance une exception et que, en demandant explicitement la copie au sein de l'opérateur d'affectation, je me laisse une chance de récupérer (et de gérer le cas échéans) cette exception
    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

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

    Informations forums :
    Inscription : Juillet 2008
    Messages : 1 580
    Points : 2 205
    Points
    2 205
    Par défaut
    Ah mais je suis tout à fait d'accord, et dans mon esprit ça c'est toujours passé comme ça, seulement ce n'est pas la première fois que j'entends l'argument de loufoque, et justement j'aimerais bien entendre les dites raisons qui font que c'est plus intéressant.

    Edit : en fait c'est ma ma faute, je voulais parlé justement que du swap (non-throwing swap?) .. En me relisant j'ai compris le pourquoi de ton intervention.


    Edit 2 : http://en.wikibooks.org/wiki/More_C%.../Copy-and-swap il est question de l'optimisation dû au passage par valeur dans le cas du copy and swap.
    "Hardcoded types are to generic code what magic constants are to regular code." --A. Alexandrescu

  9. #9
    Expert confirmé
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Décembre 2003
    Messages
    3 549
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Essonne (Île de France)

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

    Informations forums :
    Inscription : Décembre 2003
    Messages : 3 549
    Points : 4 625
    Points
    4 625
    Par défaut
    Il y a peut être des raisons qui font qu'il est plus intéressant de directement demander la copie (louffoque, pourrais tu les donner, s'il y en a)
    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
    #include <iostream>
     
    struct A
    {
        A() {}
        A(const A&) { std::cout << "A::A(const A&)" << std::endl; }
    };
     
    A make_A()
    {
        return A();
    }
     
    void take_A_1(A a)
    {
    }
     
    void take_A_2(const A& a)
    {
        A a2(a);
    }
     
    int main()
    {
        take_A_1(make_A()); // zéro copie
        take_A_2(make_A()); // une copie
    }
    Bien sûr, ça ne marche que si le compilo fait de la NRVO.
    Boost ftw

  10. #10
    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
    Ah, tiens, oui, réellement intéressant...

    Mais il reste la bonne question à se poser qui est de savoir si le compilateur utilise la NRVO, et, surtout, si tous les compilateurs actuels ne le supportent pas, quelle politique est la plus intéressante à appliquer

    C'est le cas (testé) avec Gcc 4.3.0, et il semble que ce soit le cas pour VC2005...

    As-tu une idée en ce qui concerne les autres est-ce, à l'heure actuelle plutôt la règle générale ou plutôt l'exception
    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
    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
    Points : 13 017
    Points
    13 017
    Par défaut
    Salut,
    J'ai envi de dire que dans le pire des cas (le compilo ne fait pas NRVO - Named Return Value Optimization pour les intimes), tu as le même coût qu'un passage par référence et une variable locale temporaire. Alors que si le compilo supporte la NRVO alors tu gagne une copie. Donc j'aurais tendance à conclure : passe par valeur...

  12. #12
    Expert éminent sénior
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 369
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France

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

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 369
    Points : 41 518
    Points
    41 518
    Par défaut
    Ce qu'on m'avait dit sur les copies, c'était plutôt ça:
    Code C++ : 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
    44
    45
    46
    47
    48
    49
    class A
    {
    private:
    	int a;
    public:
    	A(int a) : a(a)
    	{ }
    	A& operator=(A tmp)
    	{
    		Swap(tmp);
    		return *this;
    	}
    	void Swap(A& other)
    	{
    		std::swap(a, other.a);
    	}
    };
     
    class B
    {
    private:
    	int b;
    public:
    	B(int b) : b(b)
    	{ }
    	B& operator=(B const &src)
    	{
    		B tmp(src); //Copie explicite
    		Swap(tmp);
    		return *this;
    	}
    	void Swap(B& other)
    	{
    		std::swap(b, other.b);
    	}
    };
     
    int main(void)
    {
    	{
    		A obj(1);
    		obj = 2; //Passage par valeur: construction directe
    	}
    	{
    		B obj(1);
    		obj = 2; //Construction, puis référence, puis copie explicite
    	}
    	return 0;
    }
    SVP, pas de questions techniques par MP. Surtout si je ne vous ai jamais parlé avant.

    "Aw, come on, who would be so stupid as to insert a cast to make an error go away without actually fixing the error?"
    Apparently everyone.
    -- Raymond Chen.
    Traduction obligatoire: "Oh, voyons, qui serait assez stupide pour mettre un cast pour faire disparaitre un message d'erreur sans vraiment corriger l'erreur?" - Apparemment, tout le monde. -- Raymond Chen.

Discussions similaires

  1. conflit entre les classe java.sql.* et java.util.*;
    Par obydissonn dans le forum Langage
    Réponses: 4
    Dernier message: 26/05/2006, 19h00
  2. Réponses: 2
    Dernier message: 13/03/2006, 18h25
  3. [PHP5][MYSQL]Préserver une connexion entre les classes
    Par nesbla dans le forum SQL Procédural
    Réponses: 3
    Dernier message: 02/02/2006, 12h51
  4. Réponses: 3
    Dernier message: 22/11/2005, 12h12
  5. Comparaison entre les classes et les fonctions
    Par Ashgenesis dans le forum Langages de programmation
    Réponses: 6
    Dernier message: 08/09/2005, 20h09

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