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 :

Ma premiere classe : Aide et Critiques


Sujet :

C++

  1. #1
    Membre régulier
    Profil pro
    Inscrit en
    Avril 2008
    Messages
    150
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2008
    Messages : 150
    Points : 100
    Points
    100
    Par défaut Ma premiere classe : Aide et Critiques
    Bonjour à tous,
    Je suis tout nouveau en c++. J'ai dja fait du vb mais voila j'avais envie de m'essayer à autre chose.

    Alors j'ai donc essayé de faire une classe simple pour commencer, la classe Date. Elle me permettra de faire tous types d'operations sur les dates.

    J'aimerais avoir votre avis sur mes codes et j'aimerais vos eclaircissements ainsi que vos conseils et vos critiques. Pour info : ca compil !

    Date.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
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    #ifndef DATE_H_INCLUDED
    #define DATE_H_INCLUDED
    /* date .h Version 4*/
    class Date {
     
        int mYear;  //Day attribut
        int mMonth; //Month attribut
        int mDay;   //Year attribut
        int *mIsLeapYear;    //Is date in a leap year?
        int *mIsValid;       //Is it a valid date?
     
    public :
        Date();
        Date( int d, int m, int y);
        Date(const Date&);
        ~Date();
     
        int getDay() const;
        int getMonth() const;
        int getYear() const;
        int getIsLeapYear() const;
        int getIsValid() const;
     
        void setDay   (const int d );
        void setMonth (const int m );
        void setYear  (const int y );
        void setIsLeapYear  (const int y );
        void setIsValid  (const int y );
     
        Date operator ++();    // prefix
        Date operator ++(int); // postfix
        Date operator --();    // prefix
        Date operator --(int); // postfix
     
        Date operator =(const Date&);
     
        bool IsValid(void)  const;
        bool IsLeapYear(void)  const;
     
    };
     
     
    Date operator +=(Date&,const int&);     // increment and decrement
    Date operator -=(Date&,const int&);     // (with number of days)
     
    bool operator == (const Date&, const Date&);   // comparison operators
    bool operator != (const Date&, const Date&);
    bool operator <  (const Date&, const Date&);
    bool operator >  (const Date&, const Date&);
    bool operator <= (const Date&, const Date&);
    bool operator >= (const Date&, const Date&);
     
    int IntDate(const Date&);                    // calculations
    Date NextDate(const Date&);
    Date PreviousDate(const Date&);
     
    Date operator +(const Date&, const int&); // add number of days
    Date operator -(const Date&, const int&);
     
    #endif // DATE_H_INCLUDED
    Date.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
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    189
    190
    191
    192
    193
    194
    195
    196
    197
    198
    199
    200
    201
    202
    203
    204
    205
    206
    207
    208
    209
    210
    211
    212
    213
    214
    215
    216
    217
    218
    219
    220
    221
    222
    223
    224
    225
    226
    227
    # include <time.h>
    # include <stdlib.h>
    # include "Date.h"
     
    using namespace std;
    //**************************************************     CONSTRUCTION    ********************************************************
     
    Date::Date(int d, int m, int y) {
       mDay   = d;
       mMonth = m;
       mYear = y;
    };
    Date::Date(const Date &d) {
       mDay   = d.mDay;
       mMonth = d.mMonth;
       mYear = d.mYear;
    };
    Date::Date() {
       mDay   = 1;
       mMonth = 1;
       mYear = 2000;
    };
    Date::~Date(){
    };
     
     
    //************************************************** GETTERS AND SETTERS ********************************************************
     
    int Date::getDay () const {
    return mDay ;
    };
    int Date::getMonth () const{
    return mMonth ;
    };
    int Date::getYear () const {
    return mYear ;
    };
    int Date::getIsValid () const {
    return *mIsValid ;
    };
    int Date::getIsLeapYear () const {
    return *mIsLeapYear ;
    };
     
     
    void Date::setDay   (const int d){
        mDay = d;
        *mIsValid=-1;
    };
    void Date::setMonth (const int m){
        mMonth = m;
        *mIsValid=-1;
    };
    void Date::setYear  (const int y){
        mYear = y;
        *mIsValid=-1;
        *mIsLeapYear=-1;
    };
    void Date::setIsValid  (const int v){
        *mIsValid=v;
    };
    void Date::setIsLeapYear  (const int v){
        *mIsLeapYear=v;
    };
     
     
    //**************************************************      OPERATORS     ********************************************************
     
    Date Date::operator =(const Date &d) {
    mDay =d.mDay;
    mMonth =d.mMonth;
    mYear =d.mYear;
    return *this ;
    };
    Date Date::operator ++(int){ // postfix operator
       Date d = *this;
       *this = NextDate(d);
       return d;
    };
    Date Date::operator ++(){ // prefix operator
       *this = NextDate(*this);
       return *this;
    };
    Date Date::operator --(int){ // postfix operator, return current value
       Date d = *this;
       *this = PreviousDate(*this);
       return d;
    };
    Date Date::operator --(){ // prefix operator, return new value
       *this = PreviousDate(*this);
       return *this;
    };
    bool operator == (const Date& d1,const Date& d2){
        if (!d1.IsValid()) { return false; };
        if (!d2.IsValid()) { return false; };
        if( (d1.getDay()==d2.getDay())
    	&& (d1.getMonth()==d2.getMonth())
    	&& (d1.getYear()==d2.getYear())) {
    	return true;
        };
        return false;
    };
    bool operator !=(const Date& d1, const Date& d2){
        return !(d1==d2);
    };
    bool operator < (const Date& d1, const Date& d2){
        if (!d1.IsValid()) { return false; }; // not  meaningful, return anything
        if (!d2.IsValid()) { return false; }; // should really be an exception, but ?
        if (d1.getYear()<d2.getYear())      { return true;}
        else if (d1.getYear()>d2.getYear()) { return false;}
        else {                            // same year
    	if (d1.getMonth()<d2.getMonth())      { return true;}
    	else if (d1.getMonth()>d2.getMonth()) { return false;}
    	else { // same  month
    	    if ( d1.getDay()<d2.getDay()) { return true;}
    	    else { return false; }
    	};
        };
        return false;
    };
    bool operator > (const Date& d1, const Date& d2) {
        if (d1==d2) { return false;};  // this is strict inequality
        if (d1<d2) { return false; };
        return true;
    };
    bool operator <=(const Date& d1, const Date& d2){
      if (d1==d2) { return true; }
      return (d1<d2);
    };
    bool operator >=(const Date& d1, const Date& d2) {
        if (d1==d2) { return true;};
        return (d1>d2);
    };
    Date operator + (const Date& d, const int& days){ // IMPROVE!
        if (!d.IsValid()){return Date();};
        if (days<0) {return (d-(-days));};
        Date d1=d;
        for (int day=1;day<=days;++day){ d1=NextDate(d1); };
        return d1;
    };
    Date operator += (Date& d, const int& days){
        d = (d+days);
        return d;
    };
    Date operator - (const Date& d, const int& days) {
        if (!d.IsValid()) { return Date();};
        if (days<0)     { return (d+(-days));};
        Date d1=d;
        for (int day=0; day<days; ++day){ d1=PreviousDate(d1); }; // IMPROVE!
        return d1;
    };
    Date operator -= (Date& d, const int& days){
        return (d-days);
    };
     
    //**************************************************       METHODS      ********************************************************
    bool Date::IsLeapYear () const {
        if (*mIsLeapYear==-1) {
            if (mYear%4 != 0){
                *mIsValid=0;
                return false;
            }
            else if (mYear%100 != 0){
                *mIsValid=1;
                return true;
            }
            else if (mYear%400 != 0){
                *mIsValid=0;
                return false;
            }
            else {
                *mIsValid=1;
                return true;
            }
        }
        if (*mIsLeapYear==0) return false;
        else return true;
    };
    bool Date::IsValid() const {
        if (*mIsValid==-1) {
            if (mMonth>12 || mMonth<1) {
                *mIsValid=0;
                return false;
            }
            if (mDay>31 || mDay<1){
                *mIsValid=0;
                return false;
            }
            if ((mDay==31 && ( mMonth==2 || mMonth==4 || mMonth==6 ||mMonth==9 || mMonth==11) ) ) {
                *mIsValid=0;
                return false;
            }
            if (mDay==30 && mMonth==2){
                *mIsValid=0;
                return false;
            }
            if ((mDay==29 && mMonth==2) && (IsLeapYear()==false)){
                *mIsValid=0;
                return false;
            }
            *mIsValid=1;
            return true;
        }
        if (*mIsValid==0) return false;
        else return true;
    };
    int IntDate(const Date& d) {
        if (d.IsValid()) { return d.getYear() * 10000 + d.getMonth() * 100 + d.getDay();  };
        return -1;
    };
    Date NextDate(const Date& d){
        Date ndat;
        if (!d.IsValid()) { return ndat; };
        ndat=Date((d.getDay()+1),d.getMonth(),d.getYear());  if (ndat.IsValid()) return ndat;
        ndat=Date(1,(d.getMonth()+1),d.getYear());      if (ndat.IsValid()) return ndat;
        ndat = Date(1,1,(d.getYear()+1));          return ndat;
    };
    Date PreviousDate(const Date& d){
        Date ndat;
        if (!d.IsValid()) { return ndat; };
        ndat = Date((d.getDay()-1),d.getMonth(),d.getYear());  if (ndat.IsValid()) return ndat;
        ndat = Date(31,(d.getMonth()-1),d.getYear());     if (ndat.IsValid()) return ndat;
        ndat = Date(30,(d.getMonth()-1),d.getYear());     if (ndat.IsValid()) return ndat;
        ndat = Date(29,(d.getMonth()-1),d.getYear());     if (ndat.IsValid()) return ndat;
        ndat = Date(28,(d.getMonth()-1),d.getYear());     if (ndat.IsValid()) return ndat;
        ndat = Date(31,12,(d.getYear()-1));          return ndat;
    };
    et Voici mon Main
    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
    #include <iostream>
    #include "Date.h"
     
    using namespace std;
    int main()
    {
        Date d0;
        cout << "Voici la date d : " << d0.getDay() << "/"<< d0.getMonth()  <<"/" << d0.getYear()<< endl;
        Date d1(2,4,2003);
        cout << "Voici la date d1 : " << d1.getDay() << "/"<< d1.getMonth()  <<"/" << d1.getYear()<< endl;
        Date d2(d1);
        cout << "Voici la date d2 : " << d2.getDay() << "/"<< d2.getMonth()  <<"/" << d2.getYear()<< endl;
        //Date d3;
        //d3=d1;
        //cout << "Voici la date d3 : " << d3.getDay() << "/"<< d3.getMonth()  <<"/" << d3.getYear()<< endl;
        //Date d4;
        //d4=d1++;
        //cout << "Voici la date d4 : " << d4.getDay() << "/"<< d4.getMonth()  <<"/" << d4.getYear()<< endl;
        //Date d5;
        //d5.setDay(14);
        //cout << "Voici la date d5 : " << d5.getDay() << "/"<< d5.getMonth()  <<"/" << d5.getYear()<< endl;
     
        return 0;
    }
    Ce que je ne comprends pas c'est pour d3,d4 et d5 ca marche pas.....

    Merci pour votre aide.

  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
    Pourquoi joues-tu avec des pointeurs (que tu n'initialises même pas) dans cette classe?
    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 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
    Quelques bonnes choses par contre :
    - les setters sont mal venus AMA (faut dire que j'y suis hostile)
    - je ne vois pas l'intérêt des membres pointeurs que tu n'initialises pas
    - +=(), -=() et =() devraient renvoyer des "Date&"
    - pourquoi permettre d'avoir une date invalide ? refuse de construire des aberrations, tout le monde y gagnera.
    - Prévoit une classe de durée à termes, et va jusqu'au bout (symétrie) avec l'opérateur + et le -
    - des fois je me dis que gérer directement des time_t, c'est plus simple.
    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...

  4. #4
    Membre régulier
    Profil pro
    Inscrit en
    Avril 2008
    Messages
    150
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2008
    Messages : 150
    Points : 100
    Points
    100
    Par défaut
    Citation Envoyé par Médinoc Voir le message
    Pourquoi joues-tu avec des pointeurs (que tu n'initialises même pas) dans cette classe?
    Ce que je souhaite faire en fait c'est éviter le recalcul des int pour savoir si une date est valide ou si elle se situe dans une année bissextile.
    Trois valeurs possible : 0 false, 1 true, -1 non calculé.
    Ces int sont initialisés à -1 dans les set. Mais comme je vais les enlever je vais directement les mettre dans les constructeurs

    Citation Envoyé par Luc Hermitte
    - les setters sont mal venus AMA (faut dire que j'y suis hostile)
    - je ne vois pas l'intérêt des membres pointeurs que tu n'initialises pas
    - +=(), -=() et =() devraient renvoyer des "Date&"
    - pourquoi permettre d'avoir une date invalide ? refuse de construire des aberrations, tout le monde y gagnera.
    - Prévoit une classe de durée à termes, et va jusqu'au bout (symétrie) avec l'opérateur + et le -
    - des fois je me dis que gérer directement des time_t, c'est plus simple.
    Ok je vais essayer de suivre tt ca.


    J'ai une question concernant le .h. Pourquoi je vois régulièrement les définitions reprises avec le mot devant?
    Ca sert à quoi? Ca sert vraiment?
    Merci

  5. #5
    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
    Plutôt qu'un long discours... d'autres l'ont déjà expliqué avant (et sans doute mieux):
    http://cpp.developpez.com/faq/cpp/?page=inline

    voilà qui devrait répondre a toute tes questions.


    Par contre je comprends pas ce que t'entends par éviter le recalcul et je vois encore moins en quoi un pointeur évite ça...
    "Hardcoded types are to generic code what magic constants are to regular code." --A. Alexandrescu

  6. #6
    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,
    Pour une première classe, c'est bien
    Quelques remarques :
    ->
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    int *mIsLeapYear;    //Is date in a leap year?
    int *mIsValid;       //Is it a valid date?
    Il existe un type en C++ pour les booléens : bool qui peut prendre les valeurs true ou false.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    bool mIsLeapYear;    //Is date in a leap year?
    bool mIsValid;       //Is it a valid date?
    Je ne sais pas ce que tu voulais modéliser, mais '*' désigne un pointeur qui permet de référencer une adresse. Soit pour récupérer l'adresse d'une autre variable :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    int i(0);
    int *pi = &i; // pi 'pointe' sur i
    (*pi)==i;
    *pi = 2; // -> i == 2
    i = 4; // *pi == 4
    Soit pour gérer l'allocation dynamique :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    int *pi = new int(1);
    Mais il faut alors libérer explicitement cette mémoire allouée :
    La gestion des pointeurs est une chose délicate comme tu vas t'en rendre compte. C'est pourquoi dans la majorité des cas, on évite leur utilisation telle quel et on utilise des pointeurs intelligents : "Présentation des pointeurs intelligents en C++", par Loïc Joly.
    On a aussi les conteneurs de la STL.

    -> Toutes tes définitions de fonctions se terminent par un ';'. Ce n'est pas nécessaire :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    Date::Date(int d, int m, int y) 
    :mDay(d),mMonth(m),mYear(y)
    {
    }; // ';' en trop
    ->
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    Date::Date(int d, int m, int y) {
       mDay   = d;
       mMonth = m;
       mYear = y;
    }
    On préfère l'utilisation des listes d'initialisations :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    Date::Date(int d, int m, int y) 
    :mYear(y),mMonth(m),mDay(d)
    {}
    Pourquoi : parce que dans ta version, le déroulement est :
    1/Construction de Date : appel du constructeur de tous les membres de Date
    2/Exécution du constructeur : appel de l'opérateur d'assignation sur tous les membres.
    Avec la liste d'initialisation :
    1/ Construction de Date : appel du constructeur avec les bons paramètres.
    Et c'est tout !
    Avec des types simples comme int ou bool, ce n'est pas flagrant, mais c'est un bon réflexe à prendre.

    Note que les éléments dans ta liste d'initialisation doivent apparaître dans le même ordre que leur déclaration :
    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
    class Date {
     
        int mYear;  //Day attribut
        int mMonth; //Month attribut
        int mDay;   //Year attribut
    //...
    }
    // OK
    Date::Date(int d, int m, int y) 
    :mYear(y),mMonth(m),mDay(d)
    {//...
    }
     
    // KO : ne provoque pas d'erreur, mais certains compilateurs sortent un warning
    Date::Date(int d, int m, int y) 
    :mDay(d),mMonth(m),mYear(y)
    {//...
    }
    Pourquoi : parce que les membres sont construits dans l'ordre où ils sont déclarés dans la classe. C'est la norme qui le spécifie. Donc, lorsque tu écrits :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    Date::Date(int d, int m, int y) 
    :mDay(d),mMonth(m),mYear(y)
    Tu peux laisser croire que l'ordre de construction va être
    1/mDay
    2/mMonth
    3/mYear
    Et il n'en est rien. Ce sera toujours :
    1/mYear
    2/mMonth
    3/mDay
    Donc autant avoir une cohérence entre la lecture du code C++ et le code effectivement généré.

    -> Il te faut initialiser tout les membres de ta classe. Tes constructeurs n'initialisent pas mIsLeapYear et mIsValid. C'est une erreur. L'utilisation d'une variable non initialisée provoque un comportement indéterminé.

    -> const s'applique à ce qu'il y a à gauche : c'est la règle. L'exception est à droite s'il n'y a rien à gauche. Donc on préfère :
    ->
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    Date(const Date&);
    ~Date();
    Date operator =(const Date&);
    La norme spécifique que si ces 3 fonctions ne sont pas présentent, alors le compilateur en construit une version par défaut :
    1/ Pour le constructeur par copie : la version par défaut appel le constructeur par copie des membres et pour les membres simples se contente de copier leur valeur
    2/ Pour l'opérateur = : la version par défaut appelle l'opérateur '=' des membres
    3/ Pour le destructeur : la version par défaut appelle le destructeur des membres.
    Si ta classe ne fait rien de plus que ces opérations, i.e. tu ne gères pas de ressources particulières, alors il est fortement recommandé de ne pas implémenter ces fonctions et d'utiliser celle construite par défaut par le compilateur.

    ->
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    int getDay() const;
    int getMonth() const;
    int getYear() const;
    int getIsLeapYear() const;
    int getIsValid() const;
     
    void setDay   (const int d );
    void setMonth (const int m );
    void setYear  (const int y );
    void setIsLeapYear  (const int y );
    void setIsValid  (const int y );
    Si les membres (mYear, ...) sont privés, alors proposer un G/Setter c'est rompre cette encapsulation. Donc de deux choses l'une :
    -> Soit tu les exposes vraiment et tu les mets en public
    -> Soit tu ne les exposes pas et à ce moment pas de getter/setter. Si tu en as besoin c'est qu'en fait tu as besoin d'un service sur ta classe plus abstrait que tu n'as pas défini. Par exemple, pour ton affichage, tu pourrais faire :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    class Date
    {
    // ...
    public:
       std::string Format(); // construit un littéral.
    Ou encore utiliser une fonction libre ami :
    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
     
    class Date
    {
    // ...
    public:
    template<class streamT> 
    friend streamT& operator<<(streamT&,Date const&);
    // ... 
    };
     
    template<class streamT> 
    streamT& operator<<(streamT&os,Date const&d)
    {
       return os<< d.mDay << "/"<< d.mMonth  <<"/" << d.mYear;
    }
    // ...
    // puis
        Date d0;
        cout << "Voici la date d0 : " << d0<< endl;
    -> Je partage l'avis de Luc Hermitte sur l'état invalide. Prenons un exemple : que signifie ton opérateur '==' quand 1 ou 2 opérandes sont invalides ?

  7. #7
    gl
    gl est déconnecté
    Rédacteur

    Homme Profil pro
    Inscrit en
    Juin 2002
    Messages
    2 165
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 45
    Localisation : France, Isère (Rhône Alpes)

    Informations forums :
    Inscription : Juin 2002
    Messages : 2 165
    Points : 4 637
    Points
    4 637
    Par défaut
    Juste deux-trois petites remarques en plus de ce qui a déjà été dit :
    • Vu la façon dont sont surchargés ici les différents opérateurs et donc la façon dont ils seront utilisés, je les aurait plutôt tous laissé ici membre de la classe (avec les const qui vont bien). Même si effectivement la construction que tu as utilisée est, dans le cas générale, celle à utiliser pour des opérateurs comme + ou - (pour les opérateurs de type op= et pour les opérateurs de comparaison, je les laisserais systématiquement membre de la classe).
    • Préfères les listes d'initialisation à l'affectation dans tes constructeurs.
    • Les fonctions IntDate(const Date&), Date NextDate(const Date&), Date PreviousDate(const Date&) devraient plutôt être des membres privées de ta classe.
    • Je suis dubitatif sur l'intérêt des getter et setter. Je rejoins l'avis de 3DArchi, si le but est de pouvoir afficher une date, une fonction de formatage ou la surcharge de << me semble plus approprié.
    • J'aurais plutôt tendance à implémenter la post-incrémentation à partir de la pré-incrémentation, la post-décrémentation à partir de la pré-décrémentation.
    • De même j'aurais plutôt tendance à définir les opérateurs + à partir de +=, - à partir de -=, etc. plutôt que l'inverse comme tu le fais ici. Au passage ici, l'opérateur -= ne modifie pas la date courante, mais ce comporte comme l'opérateur -, ce qui est surprenant.
    • L'utilisation de mIsLeapYear et mIsValid est étrange, en plus d'être des pointeurs à tort et de ne pas être initialisés, je vois mal l'intérêt de mIsValid, il n'y a aucune raison d'avoir des setter dessus, si tu souhaite les utiliser en guise de "cache" interne pour l'état de la date et donc de les modifier dans des fonctions const comme IsValid(void)ou IsLeapYear(void) il devrait être mutable (je soupçonne d'ailleurs que tu utilises des pointeurs pour passer outre le const dans ce cas là).
    • Dans IsLeapYear, tu met à jour mIsValid et non mIsLeapYear.

  8. #8
    Membre régulier
    Profil pro
    Inscrit en
    Avril 2008
    Messages
    150
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2008
    Messages : 150
    Points : 100
    Points
    100
    Par défaut
    Merci à tous pour votre aide.
    Je vais maintenant la retravailler grâce à tous vos conseils.
    Merci pour tout et surtout pour ton superbe cours 3DArchi.

  9. #9
    Expert confirmé
    Avatar de Pragmateek
    Homme Profil pro
    Formateur expert .Net/C#
    Inscrit en
    Mars 2006
    Messages
    2 635
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 37
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Formateur expert .Net/C#
    Secteur : Conseil

    Informations forums :
    Inscription : Mars 2006
    Messages : 2 635
    Points : 4 062
    Points
    4 062
    Par défaut
    - les setters sont mal venus AMA (faut dire que j'y suis hostile)
    Pourquoi ?

    proposer un G/Setter c'est rompre cette encapsulation. Donc de deux choses l'une :
    -> Soit tu les exposes vraiment et tu les mets en public
    -> Soit tu ne les exposes pas et à ce moment pas de getter/setter. Si tu en as besoin c'est qu'en fait tu as besoin d'un service sur ta classe plus abstrait que tu n'as pas défini.
    Utiliser des getter/setter ne rompt en rien l'encapsulation, elle la garantie au contraire.
    En effet un getter/setter ne fait pas forcément que du forwarding vers un champ, il peut aussi contenir des règles métiers de vérification des données mais également du code technique de notification comme c'est le cas des entités "observable" dans le cadre d'une architecture MVC par exemple.

    Et même s'ils ne font que forwarder, il est possible plus tard que l'implémentation évolue et que le besoin naisse de pré/post traitements obligeant à filtrer l'accès au champ via des getter/setter.
    Dans ce cas le code client qui accédait directement au champ ne sera plus conforme à la nouvelle API car il n'y aura pas eu d'encapsulation.
    Formateur expert .Net/C#/WPF/EF Certifié MCP disponible sur Paris, province et pays limitrophes (enseignement en français uniquement).
    Mon blog : pragmateek.com

  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
    C'est un attrape-couillon.
    Avec les setter/mutateur on continue à réfléchir en terme et données et non de services rendus. Cette paire est un viol caractérisé de la Loi de Déméter.

    Il y a certes des cas où la donnée est l'interface. Mais c'est suffisamment rare pour que par défaut mes classes soient dénués de setters, et que les attributs privés restent ... privés et invisibles.

    Ici ils n'ont pour moi pas le moindre sens.
    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...

  11. #11
    Membre régulier
    Profil pro
    Inscrit en
    Avril 2008
    Messages
    150
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2008
    Messages : 150
    Points : 100
    Points
    100
    Par défaut
    Je me permets de ré-ouvrir le sujet car je rencontre quelques soucis.

    Citation Envoyé par 3DArchi
    Si les membres (mYear, ...) sont privés, alors proposer un G/Setter c'est rompre cette encapsulation. Donc de deux choses l'une :
    -> Soit tu les exposes vraiment et tu les mets en public
    -> Soit tu ne les exposes pas et à ce moment pas de getter/setter. Si tu en as besoin c'est qu'en fait tu as besoin d'un service sur ta classe plus abstrait que tu n'as pas défini.
    J'ai bien compris ce que tu voulais dire et faire de l'objet c'est respecter la notion de private avec les attributs.

    Donc j'ai revu mon code en conséquence et donc par exemple mon code pour == est devenu :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    bool operator == (const Date& d1,const Date& d2){
        if( (d1.mDay==d2.mDay)
    	&& (d1.mMonth==d2.mMonth)
    	&& (d1.mYear==d2.mYear) ) {
    	return true;
        };
        return false;
    }
    Mais là, forcément, mDay mMonth mYear c'est public... Donc le compilateur crie au scandale.
    Qu'est ce que je dois faire docteur?

    Citation Envoyé par Luc Hermitte Voir le message
    - pourquoi permettre d'avoir une date invalide ? refuse de construire des aberrations, tout le monde y gagnera.
    Je trouve ta remarque pleine de bon sens. S'il y a des problèmes autant les régler à la source. J'ai donc essayé de coder un truc mais je suis vraiment pas satisfait. Mettre NULL ou delete impliquerait utiliser des pointeurs, or mes variables ne le sont pas. Ce sont des int et des bool
    Voici mon code :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    Date::Date(int y, int m, int d):mYear(y),mMonth(m),mDay(d),mIsLeapYear(IsLeapYear()) {
        if (IsValid()==false){
            mYear=NULL;
            mMonth=NULL;
            mDay=NULL;
            mIsLeapYear=NULL;
        }
    }
    De plus, écrire
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    ),mIsLeapYear(IsLeapYear())
    c'est correct?

  12. #12
    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
    Pas besoin de IsValid()
    Si à la sortie du constructeur ce que tu as reçu ne correspond à rien, lève une exception.
    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...

  13. #13
    gl
    gl est déconnecté
    Rédacteur

    Homme Profil pro
    Inscrit en
    Juin 2002
    Messages
    2 165
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 45
    Localisation : France, Isère (Rhône Alpes)

    Informations forums :
    Inscription : Juin 2002
    Messages : 2 165
    Points : 4 637
    Points
    4 637
    Par défaut
    Citation Envoyé par -={-_-}=- Voir le message
    Donc j'ai revu mon code en conséquence et donc par exemple mon code pour == est devenu :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    bool operator == (const Date& d1,const Date& d2){
        if( (d1.mDay==d2.mDay)
    	&& (d1.mMonth==d2.mMonth)
    	&& (d1.mYear==d2.mYear) ) {
    	return true;
        };
        return false;
    }
    Mais là, forcément, mDay mMonth mYear c'est public... Donc le compilateur crie au scandale.
    Qu'est ce que je dois faire docteur?
    Et pourquoi ne pas rendre l'opérateur membre de la classe ?

  14. #14
    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
    Pourquoi le rendre membre ?
    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...

  15. #15
    Expert confirmé
    Avatar de Pragmateek
    Homme Profil pro
    Formateur expert .Net/C#
    Inscrit en
    Mars 2006
    Messages
    2 635
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 37
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Formateur expert .Net/C#
    Secteur : Conseil

    Informations forums :
    Inscription : Mars 2006
    Messages : 2 635
    Points : 4 062
    Points
    4 062
    Par défaut
    Avec les setter/mutateur on continue à réfléchir en terme et données et non de services rendus. Cette paire est un viol caractérisé de la Loi de Déméter.

    Il y a certes des cas où la donnée est l'interface. Mais c'est suffisamment rare pour que par défaut mes classes soient dénués de setters, et que les attributs privés restent ... privés et invisibles.

    Ici ils n'ont pour moi pas le moindre sens.
    Il est vrai que l'utilisation de getter/setter ne doit pas être systématique, loin de là, mais pour beaucoup d'entités orientées donnée cela est pertinent.

    Par exemple dans le référentiel métier d'une organisation il y a énormément d'entités de type "Client", "Prospect", "Facture", "Asset" qui ne rendent pas de services mais seront utilisés en input/output de services dans le cadre notamment de workflows ...
    Formateur expert .Net/C#/WPF/EF Certifié MCP disponible sur Paris, province et pays limitrophes (enseignement en français uniquement).
    Mon blog : pragmateek.com

  16. #16
    Membre régulier
    Profil pro
    Inscrit en
    Avril 2008
    Messages
    150
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2008
    Messages : 150
    Points : 100
    Points
    100
    Par défaut
    Citation Envoyé par Luc Hermitte Voir le message
    Pas besoin de IsValid()
    Si à la sortie du constructeur ce que tu as reçu ne correspond à rien, lève une exception.
    Ben si. Comment je fais pour savoir si ma date est correcte ou pas. C'est mon seul moyen.
    De plus la fonction IsValid est essentielle lors de mes additions et soustraction de jour pour obtenir une nouvelle date.

    Je suis désolé mais je n'ai pas compris.

  17. #17
    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
    Tu n'en n'as pas besoin en dehors du constructeur. Et si les paramètres sont invalides => exception et on n'en parle plus.
    Quand aux additions, additionner un nombre de jours ou de mois à une date (valide par construction) devrait toujours produire un résultat valide. Inutile de se trimballer l'état.
    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...

  18. #18
    Membre chevronné Avatar de chaplin
    Profil pro
    Inscrit en
    Août 2006
    Messages
    1 215
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2006
    Messages : 1 215
    Points : 1 819
    Points
    1 819
    Par défaut
    Si le test est fait pour plusieurs dates, il faudrait systématiquement appeler le constructeur pour faire le test .

  19. #19
    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
    Mais non, mais tu vérifies si la date est valide à la construction. Si elle l'est, elle le reste.

    ps : de toute façon on peut pas appeler explicitement le constructeur
    "Hardcoded types are to generic code what magic constants are to regular code." --A. Alexandrescu

  20. #20
    gl
    gl est déconnecté
    Rédacteur

    Homme Profil pro
    Inscrit en
    Juin 2002
    Messages
    2 165
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 45
    Localisation : France, Isère (Rhône Alpes)

    Informations forums :
    Inscription : Juin 2002
    Messages : 2 165
    Points : 4 637
    Points
    4 637
    Par défaut
    Citation Envoyé par Luc Hermitte Voir le message
    Pourquoi le rendre membre ?
    Parce que c'est une manière de régler son problème (certes pas la seule et peut être pas la meilleure).
    Mais aussi parce que je ne vois pas, pour cet opérateur là dans le cas présent[1], l'intérêt de vouloir conserver l'opérateur non-membre.

    Maintenant, si j'ai loupé quelque chose (ce qui est tout à fait possible) et que tu y vois un intérêt (c'est ce que me laisse supposer ta remarque), je suis preneur.



    [1] Il existe nombre de cas, où je vois très bien la raison.

+ Répondre à la discussion
Cette discussion est résolue.
Page 1 sur 2 12 DernièreDernière

Discussions similaires

  1. diagramme de classe AIDE pour la Correction
    Par djoufouf dans le forum Diagrammes de Classes
    Réponses: 1
    Dernier message: 18/08/2015, 17h31
  2. GoogleMapAPI.class aide script
    Par loribac dans le forum Langage
    Réponses: 2
    Dernier message: 15/11/2012, 19h04
  3. [MCD] Découverte de Merise, Premier MCD. Aide et conseil recherché
    Par Invité dans le forum Schéma
    Réponses: 4
    Dernier message: 19/03/2010, 22h02
  4. [POO] Ma premiere classe
    Par zugolin dans le forum Langage
    Réponses: 12
    Dernier message: 02/03/2009, 11h17
  5. [Classes] aide a la conception
    Par maminova77 dans le forum Langage
    Réponses: 13
    Dernier message: 24/01/2006, 21h47

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