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 :

Probleme sur ma classe Fraction


Sujet :

Langage C++

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre éclairé Avatar de Nono Sto
    Profil pro
    Inscrit en
    Mars 2009
    Messages
    350
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2009
    Messages : 350
    Par défaut Probleme sur ma classe Fraction
    Cheres amies et amis du forum

    J'ai recupere une classe C++ pour le calcul de fraction, cependant lorsque j'effectue une opération il me retourne une abération (voir image)

    En gros les affectations au variable fraction fonctionne mais lorsque le calcul s'effectue l'operateur surchargé "=" n'affecte pas la valeur, ou l'operateur surchargé "<< " n'affiche pas le resultat du calcul

    voici le bout de code impliquer

    fraction.h
    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
     
    class Fraction
    {
       int Num;
       int Denom;
    public :
    //constructeurs
       Fraction(const int, const int);
       Fraction(const int);
       Fraction();
    //Opérateuns d'action
       Fraction& operator+(const Fraction&);
       Fraction& operator+(const int&);
       Fraction& operator=(const Fraction&);
       Fraction& operator=(const int&);
     
    //Fonctions amies
       friend ostream& operator<<(ostream&, Fraction&);   //opérateurs de flux (ex : cout)
       friend istream& operator>>(istream& , Fraction&);  //opérateurs de flux (ex : cin)
       friend int Pgcd(const int&,const int&); // trouve le plus grand diviseur commun entre i1 et i2
    //Fonctions diverses
       Fraction& Simp();                      //Simplifie une fraction
       Fraction& Puis(const int&);            //comme un opérateur puissance
       Fraction& Inv();                       //Inverse la fraction
       int Signe();                           // 1 = positif ou nul      -1 = négatif
       void MemeDenom(Fraction&,Fraction&);   // met les deux fractions au meme dénominateur
    fraction.cpp
    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
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
     
    //##########################____CONSTRUCTEURS____###############################
    Fraction::Fraction(const int Numerateur,const int Denominateur)
    {
       Num=Numerateur;
       Denom =Denominateur;
    }
    //##############################################################################
    Fraction::Fraction()
    {
       Num=0;
       Denom=1;
    }
    //##############################################################################
    Fraction::Fraction(const int Entier)
    {
       Num=Entier;
       Denom =1;
    }
     
    fonction de classe
     
    Fraction& Fraction::operator+(const Fraction &F)
    {
       Fraction FRes = *this;
       Fraction FInter = F;
       MemeDenom(FInter, FRes);
       FRes.Num += FInter.Num;
       return FRes.Simp();
    }
     
    Fraction& Fraction::operator=(const Fraction &F)
    {	
        Num=F.Num;
       Denom=F.Denom;
       return *this;
    }
     
    ostream& operator<<(ostream& out, Fraction& F)
    {	
    	out << F.Num << "/" << F.Denom;
    	return out;
    }
    Merci

  2. #2
    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
    Par défaut
    Salut,
    La spécialisation de l'opérateur + retourne une référence vers un temporaire. Or le temporaire est détruit à la sortie de la fonction. Donc les valeurs deviennent invalides.

  3. #3
    Membre éclairé Avatar de Nono Sto
    Profil pro
    Inscrit en
    Mars 2009
    Messages
    350
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2009
    Messages : 350
    Par défaut
    merci
    aurais tu une solution SVP

  4. #4
    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
    Par défaut
    retourner par valeur

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

    Je voudrais attirer ton attention sur le fait que l'opérateur = est l'opérateur d'affectation, et qu'il n'a donc un sens que lorsqu'il prend comme argument... un objet du type à affecter (de type Fraction const, dans le cas présent)

    Il n'y a donc aucun intérêt de créer un opérateur d'affectation prenant un entier comme argument du simple fait que cette conversion est... prise en charge par le constructeur ad-hoc

    Par contre, les opérateurs mathématique d'addition (operator +) et de soustraction (operator -)

    Ce sont les opérateur d'addition et affectation (operator +=) et de soustraction et affectation (operator -=), voire, les opérateur d'incrémentation (operator ++) et de décrémentation (operator --) qui renvoient, effectivement, l'objet courent

    De plus, pour ce qui est de l'opérateur <<, tu peux (et c'est fortement conseillé) passer ta fraction sous la forme d'une référence constante: l'affichage s'engageant à ne pas modifier le contenu de la fraction

    En outre, il ne sert généralement pas à grand chose de passer les types primitifs (comme les int) sous la forme de référence... leur copie ne coutant pas grand chose

    A titre personnel, je choisirais enfin des noms un tout petit peu plus explicite pour les différentes fonctions que tu envisage:
    j'hésite à proposer PlusGrandCommunDiviseur pour pgcd, mais
    • Simplifie au lieu de Simp
    • Puissance au lieu de Puis
    • Inverse au lieu de Inv
    seront à mon sens bien plus compréhensibles et te faciliteront énormément la lecture du code si, dans trois mois ou un an, tu décide de te replonger dans le code

    Enfin, étant donné que tu ne renvoie finalement que deux valeur pour la fonction signe, pourquoi ne pas renvoyer directement une variable qui ne peut contenir que deux valeur: le booléen

    Pour que la réponse garde un sens, tu remplacerait la fonction signe par estPositive(), avec comme retour vrai si la fraction est effectivement positive et faux... si elle ne l'est pas.

    Ce serait toujours mieux que d'avoir une valeur prise parmi des millions d'autres indiquant un signe positif, une autre toujours prise parmi des millions d'autres indiquant un signe négatif et les millions d'autres restant inutilisées

    Allez, une dernière remarque pour la route: Tu devrais prendre l'habitude de travailler avec les listes d'initialisation.

    En effet, les membres d'une classe sont initialisés entre la parenthèse qui ferme la liste d'arguments et l'accolade ouvrante qui représente le début du code du constructeur.

    La manière dont tu crées tes constructeurs fait donc travailler en deux temps: une première initialisation (à zéro, c'est garanti par la norme) des membre entre la parenthèse fermante et l'accolade ouvrante, suivie d'une affectation dans le code.

    Dans le cas présent, cela ne pose pas trop de problèmes, car les membres de ta classes sont des primitifs, mais, dans d'autres cas cela peut réellement plomber les performances, voire (dans le cas de types non assignables) carrément être refusé à la compilation.

    Au final, ton code devrait se présenter sous la forme de
    fraction.h
    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
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    class Fraction
    {
        public:
            // constructeur par défaut
            Fraction();
            // constructeur depuis un entier
            Fraction(int num);
            // constructeur depuis un numerateur et un dénominateur
            Fraction(int num, int denom);
            // addition de deux fractions
            Fraction operator + (Fraction const &);
            // addition d'une fraction et d'un entier
            Fraction operator + (int entier);
            Fraction & operator+=(Fraction const &);
            Fraction & operator +=(int entier);
            double Puissance (int entier);
            /* ne serait il pas plus cohérent pour ces deux fonctions de renvoyer
             * un nouvel objet qui soit respectivement l'objet courent inversé
             * et l'objet courent simplifié, histoire de garder l'objet courent
             * d'origine, en cas de besoin ??
             */
            void inverse();
            void simplifie();
            /* Même s'il s'agit d'une fonction de travail avec des Fractions,
             * tu n'a pas besoin de disposer d'une instance de fraction
             * pour calculer le pgcd entre deux entiers...
             */
            static int  pgcd(int, int);
            /* idem s'il s'agit de mettre deux fraction au même dénominateur
             */
           static void memeDenominateur(Fraction &, Fraction &);
           /* à moins que tu ne veuille mettre la fraction courante et une
            * autre fraction au même dénominateur... dans ce cas, ce serait
            */
           void memeDenominateur(Fraction &);
            friend std::ostream & operator<<(std::ostream&, Fraction const &);
            friend std::istream & operator>>(std::istream &, Fraction &);
        private:
            int numerateur_;
            int denominateur_;
    };
    Et l'implémentation prendrait la forme de
    Fraction.cpp
    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
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
     
    #include "Fraction.h"
    /* cstdlib est intéressant pour avoir la fonction abs qui calcule la valeur
     * absolue d'un entier 
     */
    #include <cstdlib>
     
    Fraction::Fraction():numerateur_(0),denominateur_(1)
    {
    }
    Fraction::Fraction(int entier):numerateur_(entier),denominateur_(1)
    {
    }
    Fraction::Fraction(int num, int denom):
              numerateur_(num),denominateur_(denom)
    {
    }
    Fraction Fraction::operator+(Fraction const & f)
    {
        int num=(numerateur_*f.denominateur_) +
            (f.numerateur_*denominateur_);
        int denom=(denominateur_*f.denominateur_);
        Fraction ret(num,denom);
        return ret;
    }
    Fraction Fraction::operator+(int entier)
    {
        int num=(entier*denominateur_)+numerateur_;
        Fraction ret=(num,denominateur_);
        return ret;
    }
    Fraction& Fraction::operator +=(Fraction const & f)
    {
        Fraction temp=(*this)+f;
        numerateur_=temp.numerateur_;
        denominateur_=temp.denominateur_;
        return (*this);
    }
    Fraction& Fraction::operator +=(int entier)
    {
        Fraction temp=(*this)+entier;
        numerateur_=temp.numerateur_;
        denominateur_=temp.denominateur_;
        return (*this);
     
    }
    int Fraction::pgcd(int i1, int i2)
    {
        int more;
        int less;
        /* la valeur renvoyée ne sera en aucun cas supérieure à la valeur
         * du plus petit des deux entiers donnés...
         */
        if(i1<i2)
        {
            more=abs(i2);
            less=abs(i1);
        }
        else
        {
            more=abs(i1);
            less=abs(i2);
        }
        /* parcourons en ordre inverse toutes les valeurs comprises entre
         * la valeur la plus petite et 1
         */
        for(int i=less;i>1;--i)
        {
            /* si le reste de la division des deux entiers fournis par la valeur
             * actuelle est égale à 0, nous avons le plus grand commun diviseur
             */
            int restmore=more%i;
            int restless = less%i;
            if(restmore==0 && restless==0)
                return i;
        }
        /* S'il n'y en a pas d'autre, ce sera quoi qu'il en soit 1 */
       return 1;
    }
    void Fraction::inverse()
    {
        int temp=numerateur_;
        numerateur_=denominateur_;
        denominateur_=temp;
        /* nous aurions pu faire quelque chose proche de
         * numerateur_=^denominateur_;
         * denominateur_=^numerateur_;
         * numerateur_=^denominateur_;
         */
    }
    void Fraction::simplifie()
    {
        int pg=pgcd(numerateur_,denominateur_);
        numerateur_/=pg;
        denominateur_/=pg;
    }
    void Fraction::memeDenominateur(Fraction & f)
    {
        numerateur_*=f.denominateur_;
        f.numerateur_*=denominateur_;
        denominateur_*=f.denominateur_;
        f.denominateur_=denominateur_;
    }
    void Fraction::memeDenominateur(Fraction & f1, Fraction & f2)
    {
        f1.memeDenominateur(f2);
    }
    std::ostream& operator<<(std::ostream& ofs,Fraction const & f)
    {
    	ofs<<f.numerateur_<<"/"<<f.denominateur_;
    	return ofs;
    }
    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

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

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

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 397
    Par défaut
    Tu implémentes l'opérateur += en appelant l'opérateur +?
    Je serais plutôt du genre à faire le contraire, sauf quand il y a des considérations de performance comme de l'allocation mémoire...
    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. [PHP 5.2] Probleme sur une class
    Par franck31 dans le forum Langage
    Réponses: 2
    Dernier message: 07/08/2012, 11h09
  2. Probleme sur une classe Classe abstraite
    Par Nono Sto dans le forum Débuter
    Réponses: 3
    Dernier message: 29/01/2011, 21h58
  3. java probleme sur la methode replaceAll() de la classe String
    Par sorilazer dans le forum Collection et Stream
    Réponses: 3
    Dernier message: 02/10/2008, 11h09
  4. super() probleme sur la classe File
    Par ceres02 dans le forum Entrée/Sortie
    Réponses: 1
    Dernier message: 01/08/2007, 09h30
  5. Probleme avec la recherche directe de methodes sur une Class (API java.lang.reflect)
    Par CyberChouan dans le forum API standards et tierces
    Réponses: 14
    Dernier message: 25/01/2007, 17h12

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