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 :

[debutant]probleme avec l'operateur +


Sujet :

C++

  1. #1
    Battosaiii
    Invité(e)
    Par défaut [debutant]probleme avec l'operateur +
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
     
    plane plane::operator + (plane p)
    {
    //	int x:
    //x=passenger+p.passenger;
    //cout << "?????"<<x<<endl;
    	cout<<"passenger is : "<<passenger<<endl;
    cout<<"p.passenger is : "<<p.passenger<<endl;
    return plane(p.name,passenger+p.passenger);
    }
    quand je regarde a l'affichage ce que me donne p.passenger c'est la valeur 423522
    or dans le main .cpp j'ai :
    plane p1=plane("boeing",3);
    plane p2=plane("airbus",1);
    plane p3;
    p3=p1+p2;
    p1.display();
    p3.display();// il m'affiche n'importe quoi !!! 423522 au lieu de 4
    le int passenger se trouve definie dans la classe plane comme ceci :
    protected:
    int passenger;


    plane("boeing",3); ets defini comme ceci :




    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
     
    plane::plane(string a,int passengers)
    {
    passenger=passengers;
    cout << "the plane is called " << a<< endl;
    landingGearOn=true;
    name=a;
     
    }

    avant de poster j'ai retourne le probleme mais je trouve pas la solution .

  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 519
    Points
    41 519
    Par défaut
    on peut voir ton opérateur = ?
    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
    Battosaiii
    Invité(e)
    Par défaut
    l'operateur = marche.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
     
    plane plane::operator = (plane p)
    {
    name=p.name;
    landingGearOn=p.landingGearOn;
    OnAir=p.OnAir;
    //return p;
    return *this;
    }
    Si ca peut t'aider ...

  4. #4
    Expert éminent sénior
    Avatar de Luc Hermitte
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2003
    Messages
    5 275
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Août 2003
    Messages : 5 275
    Points : 10 985
    Points
    10 985
    Par défaut
    Il faudra quand même m'expliquer le sens de l'addition d'avions ...
    En C++, ce n'est surtout pas parce que la syntaxe nous permet de le faire qu'il le faut.

    A lire des bouts de ta classe d'avions éparpillée au travers de plusieurs fils, je vois:
    a- un héritage public
    b- une ressource brute (un pointeur brut non encapsulé pour être plus précis)
    c- des paramètres copiés
    d- une sémantique de valeur (opérateur d'affection et constructeur de recopie publics, et manipulation de valeurs qui vivent sur la pile)
    e- surcharge d'opérateurs mathématiques.

    c-, c'est le plus facile. Prends tes "gros" paramatères, et en particulier ceux qui devraient avoir une sémantique de référence, par référence constante. De là, à ce que suite à b- (mal géré) (ou ce que j'observe dansle PPS) cela corrige le problème que tu observes ici...

    Comme je te l'ai déjà dit à plusieurs reprises, a- et d- ne sont pas compatibles. Qui plus est un avion ne se manipule pas comme une valeur. Deux avions peuvent être dans le même état et pourtant être différents. De plus, et surtout, l'état d'un avion peut évoluer (cf trains sortis ou pas).

    Et d'ailleurs, passer le constructeur de recopie en protégé t'aurai empécher d'écrire
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    void f(plane);
    ... // ou encore
    {
        plane p = plane(...);
    }
    pour te réorienter sur
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    void f(plane const&);
    ...
    { 
        plane p(...);
    }
    Et de là à ce qu'il faille à termes préférer ici:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    FlyingMachine * p = new plane(...);
    // voire mieux en fait:
    boost::shared_ptr<FlyingMachine> p(new plane(...));
    e- n'a vraiment aucun sens ici ... Qui plus, ces opérateurs nécessitent une sémantique de valeur que tu t'aliennes avec ton héritage public.

    b- nécessite une attention toute particulière. Surtout lorsqu'il commence à y avoir des recopies dans l'air. Dès qu'il commence à y avoir des ressources brutes, il faut impérativement expliciter le code des constructeurs (défaut/init, recopie), et du destructeur. Et de l'opérateur d'affectation en cas de sémantique de valeur.
    Le but est d"éviter la double destruction de la ressource lorsque des copies temporaires sont réalisées. Typiquement un paramètre pris par recopie. (ce doit être traité dans la FAQ je crois)

    PS: Si tu le but de ton héritage n'était pas de permettre une substituabilité, mais une réutilisation de code, alors tu peux facilement revenir sur une sémantique de valeur. Mais je conseillerai alors de partir sur un héritage protégé ou privé. Cela évite de découvrir des bugs des mois, voire années, après.
    PPS: la recopie nécessite de ne pas oublier un seul attribut qui doit être mis à jour. Genre le nombre de passagers. Surtout avec ton approche c-
    Blog|FAQ C++|FAQ fclc++|FAQ Comeau|FAQ C++lite|FAQ BS|Bons livres sur le C++
    Les MP ne sont pas une hotline. Je ne réponds à aucune question technique par le biais de ce média. Et de toutes façons, ma BAL sur dvpz est pleine...

  5. #5
    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 519
    Points
    41 519
    Par défaut
    C'est normal, que dans ton operator = , tu retournes une copies de *this et non une référence vers *this ?
    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.

  6. #6
    Battosaiii
    Invité(e)
    Par défaut
    Luc Hermitte tu as ecrit beaucoup de choses interessantes.
    J'aimerais precises certains points :

    b- une ressource brute (un pointeur brut non encapsulé pour être plus précis)
    tu etends quoi par pointeur brute non encapsule ? par ceci plane p=plane(); ?



    une sémantique de valeur (opérateur d'affection et constructeur de recopie
    publics, et manipulation de valeurs qui vivent sur la pile)
    : tu veux dire quoi par la concretement , l'operation d'affectation
    du constructeur -> plane p=plane() ?

    -, c'est le plus facile. Prends tes "gros" paramatères, et en particulier
    ceux qui devraient avoir une sémantique de référence, par référence constante.
    De là, à ce que suite à b- (mal géré) (ou ce que j'observe dansle PPS) cela
    corrige le problème que tu observes ici...
    Tu veux que je corrige plane p en plane const& ? C'est quoi le PPS ?


    Pour la surcharge operateurs mathematique ce n'est pas important . Je sais
    qu'ajouter 2 plane n'a aucun sens.

    b- nécessite une attention toute particulière. Surtout lorsqu'il commence à y avoir
    des recopies dans l'air. Dès qu'il commence à y avoir des ressources brutes
    Dans mon code c'est quoi les ressources brutes ?


    Pour mon programme j'ai adapte en fonction de ce que j'ai compris :
    j'ai defini l'operateur de cette faconplane plane::operator + (plane const& p)
    Pourquoi faut il une reference constante ??? j'aimerais
    comprendre.

    Dans mon main :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
     
    plane *p1=new plane("boeing",3);
    plane *p2=new plane("airbus",1);
     
    plane *p3;
    p3=p1+p2;//test of the + operator
    p1->display();
    p3->display();
    Tel quel il m'affiche une erreur a cause de p3=p1+p2;

  7. #7
    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 519
    Points
    41 519
    Par défaut
    Il faut savoir que plane p=plane() est redondant, superflu et générateur d'erreurs si operator= est mal fait.

    La bonne syntaxe est juste:(sans parenthèses).
    Si tu fais plane p=plane(), tu appelles deux fois le constructeur, et une fois operator=.

    De même, operator = travaille généralement avec du passage par référence, pour ne pas appeler le constructeur de copie: donc:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    plane plane::operator=(plane &refOrig)
    {
    // blabla
    return *this;
    }
    Est erroné, car il appelle justement le constructeur de copie lors du return *this.
    Pour éviter cela, tu dois passer le type de retour de operator= de "plane" à "plane &". Ainsi,
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    plane & plane::operator=(plane &refOrig)
    {
    // blabla
    return *this;
    }
    Marchera sans appeler le constructeur de copie.
    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.

  8. #8
    Expert éminent sénior
    Avatar de Luc Hermitte
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2003
    Messages
    5 275
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Août 2003
    Messages : 5 275
    Points : 10 985
    Points
    10 985
    Par défaut
    Une ressource est une chose que tu vas allouer/ouvrir/t'accaparer et puis libérer/restituer au cours de l'exécution de ton programme. Ce va être un pot de peinture, une socket, un handle qui provient d'une bibliothèque tierce, ..., et surtout dans ton cas un pointeur.
    J'avais vu dans un autre fil que tu avais un pointeur vers une donnée temps, je crois, d'où ma remarque. Dans les constructeurs, tu procédais à une allocation, dans le destructeur à une désallocation. Ca, c'est une ressource, particulière, la plus commune de toutes.

    Maintenant, "brute". Une ressource est dite brute si tu gères, dans un contexte (/une portée), explicitement et manuellement son cycle de vie, en particulier sa libération. Le pointeur sera directement un "T*". Pour s'abstraire des problèmes relatifs à sa gestion, il est de bon ton d'encapsuler cette ressource et donc déléguer une bonne partie de sa gestion à une donnée (un objet en fait), dont la seule responsabilité est de gérer une et une seule ressource. Typiquement pour les pointeurs, on utilisera un pointeur dit intelligent, généralement à comptage de références (cf boost::shared_ptr<>, ...).
    Cette encapsulation devient très rapidement intéressante, voire incontournable si on veut, dans un objet, disposer de plusieurs ressources, et que des exceptions peuvent s'inviter à la fête.
    Tu as divers points à ce sujet dans la FAQ au sujet des pointeurs intelligents, du RAII et peut-être même des exceptions.

    Pour la sémantique de valeur, je veux dire que si tu pars dans la direction
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    Plane p1(/*gears*/false);
    Plane p2 = p1;
    p2.setGears(true);
    assert(p1.getGears() == false);
    assert(p2.getGears() == true);
    p1 = p2;
    assert(p1.getGears() == true);
    alors tu pars sur de la sémantique de valeurs. On dira que deux avions sont identiques si ils ont le même état. Si l'état change, cela veut dire que l'on accède à un autre avion. Les opérations minimales nécessaires sont : constructeur de recopie, opérateur d'affectation, et destructeur publics.

    Pour la sémantique de référence, typiquement, les objets ne vivent plus sur la pile, mais dans le free store (en gros, ils sont alloués sur le tas à l'aide de new).
    Deux avions alloués seront différents. L'état d'un avion peut évouler, cela reste toujours le même avion. Là, tu vas manipuler des pointeurs et des références. Le minimum syndical pour éviter des bugs c'est :
    - constructeur de recopie protégé si il y a une hiérarchie, privé et non défini sinon
    - opérateur d'affection privé et non défini
    Tu peux les définir en publics, mais tu auras des problèmes dans les situations suivantes:
    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
    Plane p (...);
    FlyingMachine m = p;
    // la chose la plus sournoise de toutes. Et encore, on peut faire pire:
    void f(FlyingMachine m);
    ... 
    { Plane p(...); f(p); }
    // Ceci justifie les constructeurs de recopie protégés, 
    // et la systématisation des entrées par référence constante
     
     
     
    Plane * p = new Plane(...);
    Plane * p2 = new Plane(...);
    *p2 = *p; // pas toujours un intérêt
    FlyingMachine *fm = 0;
    *fm = *p; // ka boum
    fm = new Plane(...);
    *fm = *p; // OK, mais fumé, un "delete fm; fm=p;" est mieux
     
    FlyingMachine *fm2 = new ovni(...);
    *fm = *p; 
    // alors là, c'est strictement sans aucun intérêtn dangereux, 
    // et donc à proscrire!!
    // On préfère définitivement:
    delete fm2;
    fm2 = p->clone();
    D'autre exemples de mauvaise utilisation peuvent être trouvés.



    Le PPS (Post-Postscriptum), c'est que je n'avais rien vu au sujet de la variable nombre-de-passagers dans ton opérateur d'affectation.


    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    plane *p1=new plane("boeing",3);
    plane *p2=new plane("airbus",1);
     
    plane *p3;
    p3=p1+p2;//test of the + operator
    p1->display();
    p3->display();
    Ceci est obligatoirement casse gueule. Il te faudrait à la place:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    plane *p1=new plane("boeing",3);
    plane *p2=new plane("airbus",1);
     
    plane *p3 = new Plane(); // changement ici
    *p3= *p1 + *p2;  // et ici
    // ou autre façon:
    plane p4 = *p1 + *p2;
    p1->display();
    p3->display();

    Citation Envoyé par Médinoc
    Si tu fais plane p=plane(), tu appelles deux fois le constructeur, et une fois operator=.
    Nope. Il appelle une fois le constructeur par défaut et une fois le constructeur de recopie. Et si le constructeur de recopie est déclaré "explicit", cela ne compilera pas dans mes souvenirs.
    Sur Guru Of The Week (et par conséquence dans Exceptional C++), tu as un item consacré à cela.
    Blog|FAQ C++|FAQ fclc++|FAQ Comeau|FAQ C++lite|FAQ BS|Bons livres sur le C++
    Les MP ne sont pas une hotline. Je ne réponds à aucune question technique par le biais de ce média. Et de toutes façons, ma BAL sur dvpz est pleine...

  9. #9
    Battosaiii
    Invité(e)
    Par défaut
    Dans le main j'ai :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    plane *p1=new plane("boeing",3);
    plane *p2=new plane("airbus",1);
     
    plane *p3 = new plane(); // changement ici
    *p3= *p1 + *p2;  // et ici
    // ou autre façon:
    p1->display();
    p3->display();

    mon operatru + est defini comme ceci :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    plane plane::operator + (plane const& p)
    {
    	int x;
    x=passenger+p.passenger;
    //x+=p.passenger;
    cout << "????? pourquoi on voit pas ce message "<<x<<endl;
    	cout<<"passenger is : "<<passenger<<endl;
    cout<<"p.passenger is : "<<p.passenger<<endl;
    return plane(p.name,x);
    }
    Malgre tout j'obtiens pour le nouveau plane une valur de 0 alors que ca devrait etre 4 comme on peut le voir dans le main.Des idees ?

  10. #10
    Expert éminent sénior
    Avatar de Luc Hermitte
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2003
    Messages
    5 275
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Août 2003
    Messages : 5 275
    Points : 10 985
    Points
    10 985
    Par défaut
    Relis mon précédent "PPS:". Je soupçonne fortement que cela vienne de là.
    Blog|FAQ C++|FAQ fclc++|FAQ Comeau|FAQ C++lite|FAQ BS|Bons livres sur le C++
    Les MP ne sont pas une hotline. Je ne réponds à aucune question technique par le biais de ce média. Et de toutes façons, ma BAL sur dvpz est pleine...

Discussions similaires

  1. [Debutant] Probleme avec BevelBorder
    Par devil26 dans le forum Agents de placement/Fenêtres
    Réponses: 3
    Dernier message: 09/05/2005, 09h41
  2. [debutant]probleme avec wxwidgets
    Par iwky dans le forum wxWidgets
    Réponses: 11
    Dernier message: 23/01/2005, 20h23
  3. [DEBUTANT] Probleme avec glortho
    Par barthelv dans le forum OpenGL
    Réponses: 12
    Dernier message: 23/11/2004, 14h21
  4. [DEBUTANT] probleme avec split ?
    Par matN59 dans le forum ASP
    Réponses: 6
    Dernier message: 23/10/2004, 15h47
  5. Réponses: 2
    Dernier message: 31/08/2004, 11h45

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