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 :

Surcharge d'opérateurs


Sujet :

C++

  1. #1
    Membre du Club
    Homme Profil pro
    Responsable de compte
    Inscrit en
    Juin 2014
    Messages
    215
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 54
    Localisation : France, Pyrénées Orientales (Languedoc Roussillon)

    Informations professionnelles :
    Activité : Responsable de compte

    Informations forums :
    Inscription : Juin 2014
    Messages : 215
    Points : 60
    Points
    60
    Par défaut Surcharge d'opérateurs
    Bonjour.

    Je suis parti de cette video :

    où je tente de pousser l'exercice un peu plus loin en surchargeant l'opérateur "<<" agissant sur les "struct Comment" pour faire un effet de mise en page et je rencontre un soucis dont je ne trouve la cause !

    Je déclare une struct Comment dont les instances prennent 2 paramètre (1 string et 1 int optionnel).
    Ensuite, je surcharge l'opérateur << qui est supposé afficher le commentaire avec un petit effet de mise en page.
    Le code suivant fonctionne :
    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
    #include <iostream>
    #include <list>
    #include <string>
    using namespace std;
     
    struct Comment
    {
        string Str;
        int Symbol;
        Comment(const string &str, const int &symbol= 2)
        {
            Str = str;
            Symbol = symbol;
        }
    };
     
    ostream &operator<<(ostream &COUT, Comment &comment)
    {
        int size = comment.Str.size();
        for (int i = 0; i < size; i++)
        {
            COUT << comment.Symbol;
        }
        COUT << endl << comment.Str << endl;
        for (int i = 0; i < size; i++)
        {
            COUT << comment.Symbol;
        }
        return COUT;
    }
     
    struct YoutubeChannel
    {
        string Name;
        int SubscribersCount;
     
        YoutubeChannel(string name, int subscribersCount)
        {
            Name = name;
            SubscribersCount = subscribersCount;
        }
        bool operator==(const YoutubeChannel channel) const
        {
            return this->Name == channel.Name;
        }
    };
     
    ostream &operator<<(ostream &COUT, YoutubeChannel &ytChannel)
    {
        COUT << "Name: " << ytChannel.Name << endl;
        COUT << "SubscribersCount: " << ytChannel.SubscribersCount << endl;
        ;
        return COUT;
    }
     
    struct MyCollection
    {
        list<YoutubeChannel> myChannels;
        void operator+=(YoutubeChannel &channel)
        {
            this->myChannels.push_back(channel);
        }
        void operator-=(YoutubeChannel &channel)
        {
            this->myChannels.remove(channel);
        }
    };
     
    ostream &operator<<(ostream &COUT, MyCollection &myCollection)
    {
        for (YoutubeChannel ytChannel : myCollection.myChannels)
        {
            COUT << ytChannel << endl;
        }
        return COUT;
    }
     
    int main(void)
    {
        YoutubeChannel yt1("CodeBeauty", 75000);
        YoutubeChannel yt2("Second channel", 70);
        YoutubeChannel yt3("third channel", 0);
     
        MyCollection myCollection;
        myCollection += yt1;
        myCollection += yt3;
        myCollection += yt2;
        cout << myCollection;
        myCollection -= yt1;
        Comment comment("Printing after removing a channel", 9);
        cout << comment;
        cout << endl;
        cout << myCollection;
     
        return 0;
    }

    Par contre celui-ci refuse de passer au compilateur alors que je ne tente que de remplacer mon paramètre optionnel "Symbol" int par un char :
    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
    #include <iostream>
    #include <list>
    #include <string>
    using namespace std;
     
    struct Comment
    {
        string Str;
        char Symbol;
        Comment(const string &str, const char &symbol= '&')
        {
            Str = str;
            Symbol = symbol;
        }
    };
     
    ostream &operator<<(ostream &COUT, Comment &comment)
    {
        int size = comment.Str.size();
        for (int i = 0; i < size; i++)
        {
            COUT << comment.Symbol;
        }
        COUT << endl << comment.Str << endl;
        for (int i = 0; i < size; i++)
        {
            COUT << comment.Symbol;
        }
        return COUT;
    }
     
    struct YoutubeChannel
    {
        string Name;
        int SubscribersCount;
     
        YoutubeChannel(string name, int subscribersCount)
        {
            Name = name;
            SubscribersCount = subscribersCount;
        }
        bool operator==(const YoutubeChannel channel) const
        {
            return this->Name == channel.Name;
        }
    };
     
    ostream &operator<<(ostream &COUT, YoutubeChannel &ytChannel)
    {
        COUT << "Name: " << ytChannel.Name << endl;
        COUT << "SubscribersCount: " << ytChannel.SubscribersCount << endl;
        ;
        return COUT;
    }
     
    struct MyCollection
    {
        list<YoutubeChannel> myChannels;
        void operator+=(YoutubeChannel &channel)
        {
            this->myChannels.push_back(channel);
        }
        void operator-=(YoutubeChannel &channel)
        {
            this->myChannels.remove(channel);
        }
    };
     
    ostream &operator<<(ostream &COUT, MyCollection &myCollection)
    {
        for (YoutubeChannel ytChannel : myCollection.myChannels)
        {
            COUT << ytChannel << endl;
        }
        return COUT;
    }
     
    int main(void)
    {
        YoutubeChannel yt1("CodeBeauty", 75000);
        YoutubeChannel yt2("Second channel", 70);
        YoutubeChannel yt3("third channel", 0);
     
        MyCollection myCollection;
        myCollection += yt1;
        myCollection += yt3;
        myCollection += yt2;
        cout << myCollection;
        myCollection -= yt1;
        Comment comment("Printing after removing a channel", 'F');
        cout << comment;
        cout << endl;
        cout << myCollection;
     
        return 0;
    }
    Je ne comprends absolument pas pourquoi cela refuse de fonctionner .
    Quelqu'un pourrait il m'aiguiller sur mon erreur ou bien pourquoi cela n'est pas sensé fonctionner ?

  2. #2
    Expert éminent sénior
    Avatar de Mat.M
    Profil pro
    Développeur informatique
    Inscrit en
    Novembre 2006
    Messages
    8 361
    Détails du profil
    Informations personnelles :
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Novembre 2006
    Messages : 8 361
    Points : 20 379
    Points
    20 379
    Par défaut
    pourquoi ne pas passer simplement const string & Symbol="&" ?
    Le problème de passer un char c'est que la variable locale à la structure Comment est de type string et elle ne trouve pas le caractère de terminaison en passant un char.
    En C/C++ les chaînes de caractères se terminent par '\0'.
    Puis on évite les structures car les membres de la classe sont publics par défaut

  3. #3
    Membre du Club
    Homme Profil pro
    Responsable de compte
    Inscrit en
    Juin 2014
    Messages
    215
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 54
    Localisation : France, Pyrénées Orientales (Languedoc Roussillon)

    Informations professionnelles :
    Activité : Responsable de compte

    Informations forums :
    Inscription : Juin 2014
    Messages : 215
    Points : 60
    Points
    60
    Par défaut
    Merci beaucoup pour la réponse rapide.

    Je me doutait qu'il pouvait y avoir une subtilité avec char et j'avais donc essayé avec string. J'avais cependant du faire une bourde quelque part car ça ne fonctionnait pas quand même.

    Je ne comprend pas trop pourquoi tu dis "la variable locale à la structure Comment est de type string"


    En tout cas, ça fonctionne comme je le souhaite;
    Merci.
    Sinon au lieu d'utiliser une struct, j'aurai du utiliser une class ? J'ai essayé mais n'ai pour l'instant pas réussi à faire un code fonctionnel.

    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
    #include <iostream>
    #include <list>
    #include <string>
    using namespace std;
     
    struct Comment
    {
        string Str;
        string Symbol;
        Comment(const string &str, const string &symbol = "*")
        {
            Str = str;
            Symbol = symbol;
        }
    };
     
    ostream &operator<<(ostream &COUT, Comment &comment)
    {
        int size = comment.Str.size();
        for (int i = 0; i < size; i++)
        {
            COUT << comment.Symbol;
        }
     
        COUT << endl
             << comment.Str << endl;
        for (int i = 0; i < size; i++)
        {
            COUT << comment.Symbol;
        }
     
        return COUT;
     
        /*void print_symbol(const Comment &comment)
        {
            int size = comment.Str.size();
            for (int i = 0; i < size; i++)
            {
                COUT << comment.Symbol;
            }
        }*/
    }
     
    struct YoutubeChannel
    {
        string Name;
        int SubscribersCount;
     
        YoutubeChannel(string name, int subscribersCount)
        {
            Name = name;
            SubscribersCount = subscribersCount;
        }
        bool operator==(const YoutubeChannel channel) const
        {
            return this->Name == channel.Name;
        }
    };
     
    ostream &operator<<(ostream &COUT, YoutubeChannel &ytChannel)
    {
        COUT << "Name: " << ytChannel.Name << endl;
        COUT << "SubscribersCount: " << ytChannel.SubscribersCount << endl;
        ;
        return COUT;
    }
     
    struct MyCollection
    {
        list<YoutubeChannel> myChannels;
        void operator+=(YoutubeChannel &channel)
        {
            this->myChannels.push_back(channel);
        }
        void operator-=(YoutubeChannel &channel)
        {
            this->myChannels.remove(channel);
        }
    };
     
    ostream &operator<<(ostream &COUT, MyCollection &myCollection)
    {
        for (YoutubeChannel ytChannel : myCollection.myChannels)
        {
            COUT << ytChannel << endl;
        }
        return COUT;
    }
     
    int main(void)
    {
        YoutubeChannel yt1("CodeBeauty", 75000);
        YoutubeChannel yt2("Second channel", 70);
        YoutubeChannel yt3("third channel", 0);
     
        MyCollection myCollection;
        myCollection += yt1;
        myCollection += yt3;
        myCollection += yt2;
        cout << myCollection;
        myCollection -= yt1;
        Comment comment("Printing after removing a channel", "%");
        cout << comment;
        cout << endl;
        cout << myCollection;
     
        return 0;
    }

  4. #4
    Expert éminent sénior
    Avatar de Mat.M
    Profil pro
    Développeur informatique
    Inscrit en
    Novembre 2006
    Messages
    8 361
    Détails du profil
    Informations personnelles :
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Novembre 2006
    Messages : 8 361
    Points : 20 379
    Points
    20 379
    Par défaut
    bonsoir la variable locale à la struct Comment c'est String "Str"

  5. #5
    Membre du Club
    Homme Profil pro
    Responsable de compte
    Inscrit en
    Juin 2014
    Messages
    215
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 54
    Localisation : France, Pyrénées Orientales (Languedoc Roussillon)

    Informations professionnelles :
    Activité : Responsable de compte

    Informations forums :
    Inscription : Juin 2014
    Messages : 215
    Points : 60
    Points
    60
    Par défaut
    Selon vos conseils, j'ai transformé mes struct en class, mais ça ne compile pas à cause de ces lignes :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
        bool operator==(const YoutubeChannel channel) const
        {
            return this->getName() == channel.getName();
        }
    Pour mes autres struct, celà a fonctionné. Mais je ne suis pas du tout à l'aise avec ce "this->"

    Code complet :
    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
    #include <iostream>
    #include <list>
    #include <string>
    using namespace std;
     
    class Comment
    {
    private:
        string Str;
        string Symbol;
     
    public:
        Comment(const string &str, const string &symbol = "*")
        {
            Str = str;
            Symbol = symbol;
        }
        //accesseur
        string getStr(void)
        {
            return Str;
        }
        string getSymbol(void)
        {
            return Symbol;
        }
    };
     
    ostream &operator<<(ostream &COUT, Comment &comment)
    {
        int size = comment.getStr().size();
        for (int i = 0; i < size; i++)
        {
            COUT << comment.getSymbol();
        }
     
        COUT << endl
             << comment.getStr() << endl;
        for (int i = 0; i < size; i++)
        {
            COUT << comment.getSymbol();
        }
     
        return COUT;
     
        /*void print_symbol(const Comment &comment)
        {
            int size = comment.Str.size();
            for (int i = 0; i < size; i++)
            {
                COUT << comment.Symbol;
            }
        }*/
    }
     
    class YoutubeChannel
    {
    private:
        string Name;
        int SubscribersCount;
     
    public:
        YoutubeChannel(string name, int subscribersCount)
        {
            Name = name;
            SubscribersCount = subscribersCount;
        }
        //accesseur :
        string getName(void)
        {
            return Name;
        }
     
        int getSubscribersCount(void)
        {
            return SubscribersCount;
        }
     
        bool operator==(const YoutubeChannel channel) const
        {
            return this->getName() == channel.getName();
        }
    };
     
    ostream &operator<<(ostream &COUT, YoutubeChannel &ytChannel)
    {
        COUT << "Name: " << ytChannel.getName() << endl;
        COUT << "SubscribersCount: " << ytChannel.getSubscribersCount() << endl;
        ;
        return COUT;
    }
     
    struct MyCollection
    {
        list<YoutubeChannel> myChannels;
        void operator+=(YoutubeChannel &channel)
        {
            this->myChannels.push_back(channel);
        }
        void operator-=(YoutubeChannel &channel)
        {
            this->myChannels.remove(channel);
        }
    };
     
    ostream &operator<<(ostream &COUT, MyCollection &myCollection)
    {
        for (YoutubeChannel ytChannel : myCollection.myChannels)
        {
            COUT << ytChannel << endl;
        }
        return COUT;
    }
     
    int main(void)
    {
        YoutubeChannel yt1("CodeBeauty", 75000);
        YoutubeChannel yt2("Second channel", 70);
        YoutubeChannel yt3("third channel", 0);
     
        MyCollection myCollection;
        myCollection += yt1;
        myCollection += yt3;
        myCollection += yt2;
        cout << myCollection;
        myCollection -= yt1;
        Comment comment("Printing after removing a channel", "%");
        cout << comment;
        cout << endl;
        cout << myCollection;
     
        return 0;
    }

  6. #6
    Expert éminent sénior
    Homme Profil pro
    Analyste/ Programmeur
    Inscrit en
    Juillet 2013
    Messages
    4 630
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Analyste/ Programmeur

    Informations forums :
    Inscription : Juillet 2013
    Messages : 4 630
    Points : 10 556
    Points
    10 556
    Par défaut
    Ton problème est trivial "error: passing ‘const YoutubeChannel’ as ‘this’ argument discards qualifiers [-fpermissive]"

    En gros, ton operateur == dit qu'il ne modifiera pas la classe (constant). Or ta méthode getName() ne garantie pas l'immutabilité de ta classe.
    1 méthode/objet constant(e) doit appeler que des méthodes constantes.

    Comment faire ? Je ne sais pas soit refaire la logique de ta classe, soit passer par 1 const_cast.


    Citation Envoyé par hary66 Voir le message
    Sinon au lieu d'utiliser une struct, j'aurai du utiliser une class ?
    En C++, la seule différence entre 1 struct et 1 class, c'est l'encapsulation : publique et privée respectivement.


    Citation Envoyé par hary66 Voir le message
    Mais je ne suis pas du tout à l'aise avec ce "this->"
    Le this est optionnel. Dans ton code, tu n'en as pas besoin

    Il est là pour lever les ambiguïtés pour différencier les attributs/ méthodes de ta classe des paramètres qui ont le même nom.
    Souvent on rajoute 1 underscore à la fin aux attributs ou 1 "input" par exemple aux paramètres.

    Il sert aussi à retourner/ passer 1 pointeur/ reférence de la classe.

  7. #7
    Membre du Club
    Homme Profil pro
    Responsable de compte
    Inscrit en
    Juin 2014
    Messages
    215
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 54
    Localisation : France, Pyrénées Orientales (Languedoc Roussillon)

    Informations professionnelles :
    Activité : Responsable de compte

    Informations forums :
    Inscription : Juin 2014
    Messages : 215
    Points : 60
    Points
    60
    Par défaut
    Ton problème est trivial "error: passing ‘const YoutubeChannel’ as ‘this’ argument discards qualifiers [-fpermissive]"

    En gros, ton operateur == dit qu'il ne modifiera pas la classe (constant). Or ta méthode getName() ne garantie pas l'immutabilité de ta classe.
    1 méthode constante doit appeler que des méthodes constantes.

    Comment faire ? Je ne sais pas soit refaire la logique de ta classe, soit passer par 1 const_cast.
    Je suis largué là,


    Le this est optionnel. Dans ton code, tu n'en as pas besoin

    Il est là pour lever les ambiguïtés pour différencier les attributs/ méthodes de ta classe des paramètres qui ont le même nom.
    Souvent on rajoute 1 underscore à la fin aux attributs ou 1 "input" par exemple aux paramètres.

    Il sert aussi à retourner/ passer 1 pointeur/ référence de la classe.
    Ce que je retient est que même si optionnel, il sert tout de même à lever les ambiguïtés, ce qui pour moi est bien utile !

  8. #8
    Expert éminent sénior
    Homme Profil pro
    Analyste/ Programmeur
    Inscrit en
    Juillet 2013
    Messages
    4 630
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Analyste/ Programmeur

    Informations forums :
    Inscription : Juillet 2013
    Messages : 4 630
    Points : 10 556
    Points
    10 556
    Par défaut
    Citation Envoyé par hary66 Voir le message
    Je suis largué là
    Il te manque des cours C'est le mot clef const à la fin de la ligne de la définition de ton opérateur.
    Donc tu as copié/ collé sans regarder ce qu'il y avait dans le code

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
        bool operator==(const YoutubeChannel channel) const
        {
            return this->getName() == channel.getName();
        }

  9. #9
    Membre du Club
    Homme Profil pro
    Responsable de compte
    Inscrit en
    Juin 2014
    Messages
    215
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 54
    Localisation : France, Pyrénées Orientales (Languedoc Roussillon)

    Informations professionnelles :
    Activité : Responsable de compte

    Informations forums :
    Inscription : Juin 2014
    Messages : 215
    Points : 60
    Points
    60
    Par défaut
    J'ai du supprimer les 2 CONST pour que ça passe :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     bool operator==(YoutubeChannel channel)
        {
            return this->getName() == channel.getName();
        }
    Il est vrai que je n'avait pas compris l'utilité des CONST à part le fait qu'il était prudent de les mettre étant donné que l'on ne modifiait pas la variable "YoutubeChannel" (pour le premier const).
    Pour le second const, je n'ai en effet pas compris sa nécessité qui était indiqué dans la vidéo tuto.

    Du reste, nulle part on ne tente de modifier la variable "YoutubeChannel", et je ne comprend pas bien pourquoi il y a incomparabilité à indiquer CONST.

    Concernant les cours, c'est sans doute vrai, mais c'est en pratiquant que l'on apprend et comprend mieux les choses. J'ai lu des tas de cours, mais il faut faire des exercices pour bien appréhender tout le contenu du cours.

  10. #10
    Expert éminent
    Homme Profil pro
    Ingénieur développement matériel électronique
    Inscrit en
    Décembre 2015
    Messages
    1 565
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 60
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Ingénieur développement matériel électronique
    Secteur : High Tech - Électronique et micro-électronique

    Informations forums :
    Inscription : Décembre 2015
    Messages : 1 565
    Points : 7 648
    Points
    7 648
    Par défaut
    Bonjour,

    Le problème est dû au fait qu'il manque plein de const. Le tuto explique très mal pourquoi il faut ces const.
    En fait, il faut mettre const partout sauf si le paramètre sera modifié ou si l'objet sera modifié. Ici il manque le fait d'indiquer que string getName() est const et bien évidemment la fonction de comparaison doit rester const car elle ne modifie ni l'objet ni le paramètre.
    Ça donne:
    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
        // les accesseurs sont TOUJOURS const, et retournent de préférence une const référence
        string const&  getName() const {
            return  Name;
        }
     
        int  getSubscribersCount() const {
            return  SubscribersCount;
        }
        // les mutateurs, eux ne sont jamais const, forcément ils modifient l'objet
        void  setSubscribersCount( int subscribers_count ) {
            SubscribersCount = subscribers_count ;
        }
     
        // comparaison, ni l'objet courant ni le paramètre ne sont modifiés d'où les 2 const
        bool  operator==( YoutubeChannel const& channel ) const {
            return  getName() == channel.getName();
        }
    Il en manque plein d'autres. Il y a d'ailleurs plein d'erreurs dans le tuto. Un des principes de base du C++ est la const-correctess, je t'encourage à te renseigner sur ce sujet.

  11. #11
    Membre du Club
    Homme Profil pro
    Responsable de compte
    Inscrit en
    Juin 2014
    Messages
    215
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 54
    Localisation : France, Pyrénées Orientales (Languedoc Roussillon)

    Informations professionnelles :
    Activité : Responsable de compte

    Informations forums :
    Inscription : Juin 2014
    Messages : 215
    Points : 60
    Points
    60
    Par défaut
    Il faut bien comprendre qu'un débutant ne peut absorber toutes les finesses et la rigueur du C++.
    Ce qui explique peut être les manques de précision du tuto.
    En tout cas, j'espère que ce ne sont pas réellement des erreurs comme dit dans votre réponse, mais plutôt des "allégement".

    Quand à la const-correctess, ça me semble une finesse de programmeur professionnel dont je n'ai jamais entendu parler auparavant.
    Encore une fois, il est difficile en tant que débutant de digérer tout d'un coup.

  12. #12
    Membre expert
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2011
    Messages
    739
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Hérault (Languedoc Roussillon)

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

    Informations forums :
    Inscription : Juin 2011
    Messages : 739
    Points : 3 627
    Points
    3 627
    Par défaut
    Citation Envoyé par hary66 Voir le message
    Quand à la const-correctess, ça me semble une finesse de programmeur professionnel dont je n'ai jamais entendu parler auparavant.
    Absolument pas. La const-correctness est une chose qui se voit très tôt dans n'importe quel bon cours. C'est à dire dans le chapitre concernant la création de fonction. Le mot clef const peut se voir même avant (introduction en douceur) puis dans les fonctions membres lorsqu'on parle de structure et classe. Quand je regarde le cours de zeste de savoir, const est introduit en même temps que les variables.

    La const-correctness n'est que l'application d'une règle simple: mettre const quand on ne modifie pas l'objet.

    Lorsque je vois votre code, certains point me font dire que vos tutos sont plutôt moyens: utilisation de using namespace std, utilisation de std::list (il faut de très bonne raison pour la préférer à std::vector), pas d'utilisation de la liste d'initialisation, etc.

  13. #13
    Membre du Club
    Homme Profil pro
    Responsable de compte
    Inscrit en
    Juin 2014
    Messages
    215
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 54
    Localisation : France, Pyrénées Orientales (Languedoc Roussillon)

    Informations professionnelles :
    Activité : Responsable de compte

    Informations forums :
    Inscription : Juin 2014
    Messages : 215
    Points : 60
    Points
    60
    Par défaut
    Arf !

    J'avais réussi à bricoler un peu ce WE avec les class et la surcharge d'opérateur et là, vous me ficher tout à terre !
    Ca me décourage !


    Pour le const, en effet, je l'utilisait un peu, c'est un bon garde fou.
    Pour le using namespace std, quand on bricole, c'est vraiment pénible d'écrire std:: à chaque fois ! Après, je peu comprendre que ce soit plus rigoureux.

    Pour l'utilisation de std::list au lieu de std::vector, je n'ai pas de justification.

  14. #14
    Expert éminent sénior
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 614
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 614
    Points : 30 626
    Points
    30 626
    Par défaut
    Salut,
    Citation Envoyé par hary66 Voir le message
    J'ai du supprimer les 2 CONST pour que ça passe :
    Holla!!!!

    Voici une petite règle qui devrait t'éviter énormément de soucis par la suite:
    On ne supprime JAMAIS le mot clé const si on a de bonne raisons de considérer que la donnée manipulée ne doit pas être modifiée
    On pourrait même aller plus loin, en fait...

    On sait que toute donnée qui n'est pas explicitement indiquée comme étant constante cours le risque majeur d'être modifiée (Merci Mr Obvious ).

    C'est ce qui se passe "par défaut" comme par exemple dans le code
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    int main(){
        int i = 3; // i n'est pas déclaré constant
        /* ... */
        i = 10; // je peux donc modifier sa valeur
    }
    Hé bien, je vais peut-être te surprendre, mais cette c**rie est sans doute à l'origine de base de 90% des bugs que tu pourras rencontrer.

    Et ce pour une raison toute simple:

    On conseille généralement de transmettre toutes les données "dont la taille est supérieure à celle d'un type primitif (comprend: dés que l'on n'a pas affaire à un char, un short, un int, un long, un long long, un float, un double ou un long double, ainsi que les versions "unsigned" des types qui les supportent) de transmettre la donnée sous forme de référence pour éviter les problèmes liés à la "perte de temps" (et de ressources) lors de la copie.

    Seulement, une référence va -- littéralement -- agir comme un alias de la donnée d'origine au niveau de la fonction appelée.

    Cela implique que si tu modifie un paramètre (transmis par référence ou par pointeur) dans une fonction, les modifications que tu apportées dans la fonction vont se répercuter au niveau de la variable d'origine. C'est le cas dans un code qui pourrait être aussi simple que
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    void foo(int & param){
        param += 3; // ajoute 3 à la valeur de param
    }
    int main(){
        int i = 6;
        foo(i); // appelle foo en lui transmettant i par référence
        std::cout<<i<<"\n"; // affiche ... 9, car les modifications apportées par
                            // foo ont été répercutées sur i
    }
    Ce code est tout à fait valide, et peut même être "parfaitement justifié" dans certaines situations... Pour autant que l'on ait la certitude absolue que le fait de modifier la valeur de la variable "d'origine" soit réellement justifié et que l'utilisateur de notre fonction foo ne fera pas une connerie en l'appelant dans une situation dans laquelle cela ne se justifie pas ou qui pourrait poser problème.

    Hé bien, il faut se dire que de telles situations ne peuvent tout simplement pas arriver lorsqu'une donnée est déclarée constante, et pour cause, vu qu'on dit explicitement au compilateur que "cette donnée n'est pas destinée à être modifiée" (encore merci Mr Obvious ).

    Or, le compilateur va se mettre à râler chaque fois qu'il se rendra compte qu'une donnée "soit disant constante" risque d'être modifiée. Et il sera généralement "plus têtu" que toi

    Si bien que "dans l'idéal", nous ne devrions faire en sorte de ne travailler -- du moins, dans la mesure du possible -- qu'avec des données constantes

    Au lieu de supprimer le mot clé const à gauche et à droite "pour que le compilateur accepte de faire son travail", tu devrais donc envisager de rajouter ce mot clé "partout où le compilateur se plaint" de passer d'une donnée constante à une donnée non constante.

    Parce que c'est -- justement -- en refusant d'apporter des (éventuelles) modifications à une donnée "qui n'est pas sensée être modifiée" qu'il pourra t'éviter une très grosse majorité des soucis.

    A tel point que, si j'avais un ordre logique à conseiller, ce serait plutôt:
    1. on déclare toutes les données et tous les paramètres comme constant(e)s "par défaut"
    2. on déclare toutes les fonctions membres de nos classes comme "ne permettant pas la modification de l'objet à partir duquel elles sont appelées" (constante, donc) "par défaut"
    3. on ne supprime le mot clé const des fonctions membres que ... s'il est "évident" que le comportement attendu de la fonction considérée consiste à modifier l'objet à partir duquel elle est appelée, et que l'on n'a donc "pas d'autre choix"
    4. on ne supprime le mot clé const d'une donnée (ou d'un paramètre) que ... s'il est évident que la donnée manipulée devra être modifiée, et que l'on n'a donc "pas d'autre choix"
    5. on limite le fait de manipuler une donnée "non constante" à des portions de code qui soient les plus courtes possibles et qui, "dans l'idéal", se limitent au seul fait d'apporter la modification envisagée

    PS savais tu, d'ailleurs, que c'est -- en gros -- l'approche suivie "par défaut" par la grosse majorité des langages dit "fonctionnels"
    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

  15. #15
    Expert éminent sénior
    Homme Profil pro
    Analyste/ Programmeur
    Inscrit en
    Juillet 2013
    Messages
    4 630
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Analyste/ Programmeur

    Informations forums :
    Inscription : Juillet 2013
    Messages : 4 630
    Points : 10 556
    Points
    10 556
    Par défaut
    on peut rajouter qu'il y a 3 types de paramètres : entrée, sortie, entrée/ sortie.
    Et donc le mot clef const permet d'avoir les paramètres entrée, et les pointeurs/ références des paramètres sortie et entrée/ sortie.
    Ensuite, les P.O.D (plain old data) n'ont pas besoin d'être constants parce qu'elles sont transmises par valeur. C'est surtout pour les pointeurs/ références.

    Lien wiki paramètre en français

  16. #16
    Expert éminent sénior
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 614
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 614
    Points : 30 626
    Points
    30 626
    Par défaut
    Citation Envoyé par foetus Voir le message
    Et donc le mot clef const permet d'avoir les paramètres entrée, et les pointeurs/ références des paramètres sortie et entrée/ sortie.
    Ensuite, les P.O.D (plain old data) n'ont pas besoin d'être constants parce qu'elles sont transmises par valeur. C'est surtout pour les pointeurs/ références.

    Lien wiki paramètre en français
    Et encore, les POD ne sont finalement qu'une de ces "rares occasions" dont je parlais, et rien n'empêche de les transmettre par référence (constante en cas de besoin)...

    Prenons l'exemple tout simple d'une structure proche de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    struct Color{
       int red;
       int green;
       int blue;
    };
    ou de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    struct Point{
        float x;
        float y;
        float z;
    };
    Voici bel et bien deux structures que l'on pourra considérer comme étant des POD, vu qu'elles ne font vraiment qu'amalgamer des données (de type primitif) qui ne prennent réellement leur sens que parce qu'elles sont destinées à "travailler ensemble".

    Cependant, on peut clairement considérer que ce sont des données dont "la taille est supérieure à celle d'un type primitif" (surtout si le padding entre en jeu ).

    Personnellement, si je dois transmettre des données de ces types, je le ferai sous la forme de référence (éventuellement constante) plutôt que par valeur, et ce, malgré le fait que la création d'une copie ne coute sans doute "pas beaucoup plus cher" que le passage par référence

    De plus, lorsqu'une de ces données est fournie en paramètre à une fonction, il reste la question de savoir si les modifications apportée au paramètre par la fonction appelée doivent être répercutées sur la donnée d'origine ou non.

    Et si c'est le cas, la véritable question finale sera de savoir si on préfère écrire un code proche de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    int main(){
        Point p;
        laFonctionQuiModifieUneReference(p); // transmis par référence, les modifications sont répercutées
    }
    ou
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    int main(){
        point p;
        p = laFonctionQuiModifieUneCopie(p); // transmis par valeur, les modifications étant récupérées
                                             // au travers du retour de la fonction
    }
    Ma "fainéantise naturelle" tendrait sans doute à préférer la première version
    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

  17. #17
    Rédacteur/Modérateur


    Homme Profil pro
    Network game programmer
    Inscrit en
    Juin 2010
    Messages
    7 115
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : Canada

    Informations professionnelles :
    Activité : Network game programmer

    Informations forums :
    Inscription : Juin 2010
    Messages : 7 115
    Points : 32 967
    Points
    32 967
    Billets dans le blog
    4
    Par défaut
    Ça a sûrement déjà été dit mais ton code nmanque de const-correctness, fait des copies partout et tes opérateurs += sont faux.
    La syntaxe normale est CLASS& operator+=(const CLASS& other) { ... return *this; }.
    Ce serait bien de donner l'erreur que ton compilo te retourne, parce que "ça marche pas" en fournissant 100 lignes de code, et mentionnant les opérateurs << qui semblent corrects, ça aide pas à t'aider...
    Et using namespace std; ne devrait pas être utilisé ici.
    Pensez à consulter la FAQ ou les cours et tutoriels de la section C++.
    Un peu de programmation réseau ?
    Aucune aide via MP ne sera dispensée. Merci d'utiliser les forums prévus à cet effet.

  18. #18
    Membre du Club
    Homme Profil pro
    Responsable de compte
    Inscrit en
    Juin 2014
    Messages
    215
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 54
    Localisation : France, Pyrénées Orientales (Languedoc Roussillon)

    Informations professionnelles :
    Activité : Responsable de compte

    Informations forums :
    Inscription : Juin 2014
    Messages : 215
    Points : 60
    Points
    60
    Par défaut
    Je ne suis pas certain de bien comprendre :

    Citation Envoyé par koala01 Voir le message
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    Point p;
    void laFonctionQuiModifieUneReference(p); // transmis par référence, les modifications sont répercutée
    ou
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    point p;
    p = laFonctionQuiModifieUneCopie(p); // transmis par valeur, les modifications étant récupérées
                                         // au travers du retour de la fonction
    ne devrait pas plutot être :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    Point p;
    void laFonctionQuiModifieUneReference(Point &p); // transmis par référence, les modifications sont répercutée
    et pour m'assurer que je comprend bien :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    Point p;
    Point laFonctionQuiModifieUneCopie(Point point){
    (modification de point;)
    return point;
    }
    p = laFonctionQuiModifieUneCopie(p); // transmis par valeur, les modifications étant récupérées
                                         // au travers du retour de la fonction

  19. #19
    Expert confirmé

    Homme Profil pro
    Directeur de projet
    Inscrit en
    Mai 2013
    Messages
    1 329
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Yvelines (Île de France)

    Informations professionnelles :
    Activité : Directeur de projet
    Secteur : Service public

    Informations forums :
    Inscription : Mai 2013
    Messages : 1 329
    Points : 4 146
    Points
    4 146
    Par défaut
    Bonjour,

    Non, l'écriture de Koala est correcte mais c'est une écriture d'usage et non de déclaration de la fonction (qui correspond à ce que tu écris).

    Salutations
    Ever tried. Ever failed. No matter. Try Again. Fail again. Fail better. (Samuel Beckett)

  20. #20
    Membre du Club
    Homme Profil pro
    Responsable de compte
    Inscrit en
    Juin 2014
    Messages
    215
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 54
    Localisation : France, Pyrénées Orientales (Languedoc Roussillon)

    Informations professionnelles :
    Activité : Responsable de compte

    Informations forums :
    Inscription : Juin 2014
    Messages : 215
    Points : 60
    Points
    60
    Par défaut
    Je pleure !
    Je ne comprend rien du tout !
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    Point p;
    void laFonctionQuiModifieUneReference(p); // transmis par référence, les modifications sont répercutée
    L'usage d'une fonction n'est pas précédé par le type de renvoi normalement !
    D'autre part, si cette fonction modifie une référence, elle doit prendre une référence (ou un pointeur) en paramètre, hors p est une variable de type Point, le paramètre ne devrait-il donc pas être présenté à la fonction précédé du & ?

    Pour le second extrait de code, mis à par p déclaré de type point au lieu de type Point, on peut en effet comprendre. Mais si je veut être certain de bien saisir, il me semble que cette écriture n'est pas fausse ?
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    Point p;
    Point laFonctionQuiModifieUneCopie(Point point){
    (modification de point;)
    return point;
    }
    p = laFonctionQuiModifieUneCopie(p); // transmis par valeur, les modifications étant récupérées
                                         // au travers du retour de la fonction
    Je m'excuse d'ergoter de manière si insistante, mais je veux clarifier tout doutes.

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

Discussions similaires

  1. Réponses: 2
    Dernier message: 02/02/2020, 18h22
  2. Réponses: 16
    Dernier message: 19/02/2010, 09h40
  3. Demande d'aide pour débutant.
    Par pixee dans le forum jQuery
    Réponses: 6
    Dernier message: 31/07/2009, 10h13
  4. [PHP 5.3] Demande aide pour un débutant
    Par xenon1405 dans le forum Langage
    Réponses: 3
    Dernier message: 03/06/2009, 14h48
  5. demande d'aide pour débutant
    Par libremax dans le forum Langage
    Réponses: 6
    Dernier message: 19/11/2008, 19h03

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