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 :

[debat] Le mot clef const


Sujet :

C++

  1. #21
    Membre régulier

    Inscrit en
    Octobre 2010
    Messages
    50
    Détails du profil
    Informations forums :
    Inscription : Octobre 2010
    Messages : 50
    Points : 70
    Points
    70
    Par défaut
    Citation Envoyé par gl Voir le message
    Et qu'est ce qui empêche ici de faire une fonction Display() qui modifie l'objet ?
    Dans ce cas-ci, rien en effet. Je me suis contenté d'obliger la fonction DoSomething() à n'utiliser que des méthodes garantissant qu'elles ne modifient pas l'objet. Ces méthodes peuvent en effet contenir des erreurs, mais c'est un autre problème.

    Considérons donc ce problème: pour le développeur de la méthode Display(), comment peut-il s'assurer qu'il ne modifie pas l'objet par inadvertance? Encore une fois, c'est possible en séparant la classe en partie immuable/partie variable:


    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 MyTypeReadOnly {
    protected:
        virtual int getX() = 0;
        virtual float getF() = 0;
    public:
        // La classe n'a que des getters, donc impossible de modifier l'objet
        void Display() { cout << getX() << " " << getF() << endl; }
    };
     
    class MyType : public MyTypeReadOnly {
        int m_x;
        float m_f;
    protected:
        int getX() { return m_x; }
        float getF() { return m_f; }
    public:
        // La classe a accès à ses membres de données, donc elle peut le modifier
        void Initialize() { m_x = 0; m_f = 0.0f; }
    };
    À moins que le développeur de MyType ne modifie l'objet dans les getters, ce qui est une erreur très évidente (à ce titre, il pourrait aussi bien faire des const_cast pour contourner const), la méthode Display n'a aucun moyen de modifier l'objet.

    Avoir une classe Immuable et avoir accès à une instance de manière immuable ne sont pas la même chose.
    Oui. Const ne rend pas une classe immuable, const donne accès à une instance de manière immuable (il limite l'usage aux fonctions const). Or, donner accès à une instance de manière immuable, c'est bien ce que j'ai fait ici en présentant une interface immuable à mon instance.

    Dans le contre-exemple que tu donnes, si vector<T> avait une interface immuable, il me suffirait de le passer en tant que cette interface plutôt qu'en tant que const vector<T> pour arriver à la même garantie.

    Citation Envoyé par Joel F
    Sauf que encore, dans ton exemple, mettre des const comme préconisé, ne change rien au comportement du programme ni du programmeur ...
    ... et est donc totalement inutile? En fait oui, mettre des const sur les méthodes d'accès oblige toute méthode appelée par ces méthodes à être const aussi, de façon récursive à l'infini. Donc, l'impact sur le code est potentiellement énorme. Tandis que absence de const + interfaces immuables spécifie un contrainte localisée et spécifique.

  2. #22
    En attente de confirmation mail

    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Août 2004
    Messages
    1 391
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 33
    Localisation : France, Doubs (Franche Comté)

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

    Informations forums :
    Inscription : Août 2004
    Messages : 1 391
    Points : 3 311
    Points
    3 311
    Par défaut
    En gros tu dis qu'à la place de mettre des const tu préfères une interface clair qui identifie clairement ce qui modifie l'objet de ce qui ne le modifie pas ?

    Mais si tu as fais cette identification, rajouter des const là où il faut devient quasi-immédiat et un utilisateur de ton code ne pourra pas (*) appeler une fonction qui ne modifie pas l'objet sans recevoir un avertissement (une erreur) du compilo, ce qui est quand même bien plus "fort" (dans le sens se contourne moins vite) qu'un commentaire dans un code ou qu'une documentation de l'interface de ta classe.

    (*) Alors oui, on peut mettre des const_cast, mais faire cà c'est dire au compilo : "je suis assez grand pour savoir ce que je fais, alors tu me lâches !", donc si, const garantie l'immuabilité, mais comme le C++ permet tout et n'importe quoi, il permet en partie le n'importe quoi, donc le viole de cette immuabilté.

    (Pour la mutabilité, ca correspond à quelque chose de précis, et les variables mutables n'ont pas à impacter fortement la vision de l'objet qu'aura un utilisateur).

  3. #23
    Membre régulier Avatar de Chessmaster1966
    Inscrit en
    Juillet 2010
    Messages
    63
    Détails du profil
    Informations forums :
    Inscription : Juillet 2010
    Messages : 63
    Points : 74
    Points
    74
    Par défaut
    Citation Envoyé par Dr Dédé Voir le message
    Dans ce cas-ci, rien en effet. Je me suis contenté d'obliger la fonction DoSomething() à n'utiliser que des méthodes garantissant qu'elles ne modifient pas l'objet. Ces méthodes peuvent en effet contenir des erreurs, mais c'est un autre problème.

    Considérons donc ce problème: pour le développeur de la méthode Display(), comment peut-il s'assurer qu'il ne modifie pas l'objet par inadvertance? Encore une fois, c'est possible en séparant la classe en partie immuable/partie variable:


    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 MyTypeReadOnly {
    protected:
        virtual int getX() = 0;
        virtual float getF() = 0;
    public:
        // La classe n'a que des getters, donc impossible de modifier l'objet
        void Display() { cout << getX() << " " << getF() << endl; }
    };
     
    class MyType : public MyTypeReadOnly {
        int m_x;
        float m_f;
    protected:
        int getX() { return m_x; }
        float getF() { return m_f; }
    public:
        // La classe a accès à ses membres de données, donc elle peut le modifier
        void Initialize() { m_x = 0; m_f = 0.0f; }
    };
    À moins que le développeur de MyType ne modifie l'objet dans les getters, ce qui est une erreur très évidente (à ce titre, il pourrait aussi bien faire des const_cast pour contourner const), la méthode Display n'a aucun moyen de modifier l'objet.

    Oui. Const ne rend pas une classe immuable, const donne accès à une instance de manière immuable (il limite l'usage aux fonctions const). Or, donner accès à une instance de manière immuable, c'est bien ce que j'ai fait ici en présentant une interface immuable à mon instance.

    Dans le contre-exemple que tu donnes, si vector<T> avait une interface immuable, il me suffirait de le passer en tant que cette interface plutôt qu'en tant que const vector<T> pour arriver à la même garantie.

    ... et est donc totalement inutile? En fait oui, mettre des const sur les méthodes d'accès oblige toute méthode appelée par ces méthodes à être const aussi, de façon récursive à l'infini. Donc, l'impact sur le code est potentiellement énorme. Tandis que absence de const + interfaces immuables spécifie un contrainte localisée et spécifique.
    Tu fais erreur !!!

    Si tu arrives à modifier les données membres par la méthode Initialize() c'est parce qu'elles sont des variables toute variable est modifiable.

    Je le répète apparement certains n'ont pas bien compris le sens de "const"
    Utiliser "const" pour une fonction membre c'est d'assurer à l'appelant que cette dernière de modifiera pas les données membres de quelque mamière que ce soit.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
     int getX() { return m_x; }
    Par exemple :
    Dans ta fonction getX() si tu ajoute le mot clé "const" cela donnera ceci :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
     int getX() const { return m_x; }
    et te permettra d'éviter si tu ne met pas "const" ceci :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
     int getX()
     { 
        m_x = 10;
        return m_x;
     }
    Les erreurs d'inadvertances par les programmeur sont fréquentes lorsque l'on programme des heures durant. Comme le dit gl si tu pars du principe que tu ne fera pas d'erreurs alors tu est un "big boss" mais j'en doute tout programmeur aussi fort qu'il est fait des erreurs. Alors de mettre un "const" ç ne coûte absoluement rien si ce n'est que de placer un mot de 5 lettres en plus. Tu règle tout au moment de la compilation.

    Dans l'exemple suivant si tu met un "const" alors que tu modifies une donnée membre cela provoquera une erreur de compilation :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
     int getX() const
     { 
        m_x = 10; //Erreur: la fonction est const.
        return m_x;
     }
    Comme le dit gl (encore) en utilisant "const_cast " tu fais un acte délibéré de modifier une valeur et en plus ce n'est pas possible étant donnée que "const_cast" n'accepte que des pointeurs ou références.

    Et puis une donnée membre "const" restera toujours un "const" donc non modifiable utiliser un "const_cast" est impossible et si c'est possible donne moi un exemple !
    Le bonheur est sans raison

  4. #24
    yan
    yan est déconnecté
    Rédacteur
    Avatar de yan
    Homme Profil pro
    Ingénieur expert
    Inscrit en
    Mars 2004
    Messages
    10 033
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France, Ille et Vilaine (Bretagne)

    Informations professionnelles :
    Activité : Ingénieur expert
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Mars 2004
    Messages : 10 033
    Points : 13 968
    Points
    13 968
    Par défaut
    Citation Envoyé par Dr Dédé Voir le message
    Oui. Const ne rend pas une classe immuable, const donne accès à une instance de manière immuable (il limite l'usage aux fonctions const). Or, donner accès à une instance de manière immuable, c'est bien ce que j'ai fait ici en présentant une interface immuable à mon instance.

    si ta classe est immuable tu donne un accès immuable, y as rien d'étrange. Mais tu ne peut qu'avoir un accès immuable du cou... Pour un vecteur qui contiens des données j'aimerai quand même pouvoir modifier de temps en temps les valeurs.
    De plus je vois pas l'intérêt d'avoir une classe immuable qui ne me donne que des accésseurs

  5. #25
    Membre régulier Avatar de Chessmaster1966
    Inscrit en
    Juillet 2010
    Messages
    63
    Détails du profil
    Informations forums :
    Inscription : Juillet 2010
    Messages : 63
    Points : 74
    Points
    74
    Par défaut
    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 A
    {
            double a;
            mutable double b;
     
            public:
                A(double number1, double number2) : a(number1), b(number2){}
                double GetA() const {return a;}
                double GetB() const {return b;}
                void SetA()  const { a *= 25;}
                void SetB() const { b = a * 89;}
    };
     
    int main()
    {
     
       A a(14, 45);
       a.SetA(); //Erreur: a n'est pas "mutable"
       a.SetB(); //Ok: b est "mutable"
       cout << a.GetA() << " " << a.GetB();
     
     system("pause");
     
     return EXIT_SUCCESS;
    }
    La classe A est élégante, n'est-ce pas ?

    La "mutabilité" permet de contourner le "const" d'une fonction c'est juste un moyen élégant de contournement mais honêtement je n'en vois pas l'utilité si ce n'est que (peut-être) dans certains cas et encore.

    Faire l'usage du mot clé "mutable" c'est être conscient de ce que tu fais en matière de modification de données membres par une fonction "const".

    Encore une fois (je sais, je me répète) utiliser le mot "const" est vraiment très efficace pour maintenir des classes propres et élégantes.
    Le bonheur est sans raison

  6. #26
    Membre chevronné
    Avatar de Joel F
    Homme Profil pro
    Chercheur en informatique
    Inscrit en
    Septembre 2002
    Messages
    918
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 44
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Chercheur en informatique
    Secteur : Service public

    Informations forums :
    Inscription : Septembre 2002
    Messages : 918
    Points : 1 921
    Points
    1 921
    Par défaut
    faudrait voir à pas faire manger le troll :o

  7. #27
    Membre régulier

    Inscrit en
    Octobre 2010
    Messages
    50
    Détails du profil
    Informations forums :
    Inscription : Octobre 2010
    Messages : 50
    Points : 70
    Points
    70
    Par défaut
    Citation Envoyé par Joel F Voir le message
    faudrait voir à pas faire manger le troll :o
    Tiens, je l'attendais depuis un bout celle-là.

    On croirait que je blesse certaines personnes, à voir le nombre de "désapprobations" que mes messages reçoivent. Est-il si dur d'accepter que certains ont un point de vue différent? Je n'ai dit que des choses que je pouvais argumenter clairement et que j'ai illustrées ouvertement. Même si j'ai peut-être tort, ce que je ne crois pas, je crois avoir une discussion intéressante ici que j'ai rarement l'occasion d'avoir. Je doute que vous ayez souvent remis en question le bien fondé du const-correctness, et tiens, je vous donne l'occasion de le faire.

    Citation Envoyé par yan
    si ta classe est immuable tu donne un accès immuable, y as rien d'étrange. Mais tu ne peut qu'avoir un accès immuable du cou... Pour un vecteur qui contiens des données j'aimerai quand même pouvoir modifier de temps en temps les valeurs.
    De plus je vois pas l'intérêt d'avoir une classe immuable qui ne me donne que des accésseurs
    Je ne suis pas sûr que tu aies compris mon exemple. L'interface MyTypeReadOnly donne accès immuable à une classe variable, MyType. Quand tu passes un MyType*, tu donnes plein accès avec possibilité de modification. Quand tu passes la même instance en tant que MyTypeReadOnly*, tu ne donnes accès qu'aux méthodes qui garantissent de ne pas modifier la classe. C'est la même chose que const: quand tu passes un T*, tu donnes accès à toutes les méthodes, et quand tu passes un const T*, tu ne donnes accès qu'aux méthodes const. Sauf qu'au lieu d'avoir les méthodes const et non-const dans la même déclaration de classe, tu les sépare en deux déclarations, la variable héritant de l'immuable. Les fonctions qui ne doivent pas modifier l'objet peuvent être définies dans l'immuable, garantissant ainsi qu'elles ne modifient rien. Du coup, plus besoin de const.

    Donc, pour reprendre ta formulation, je n'ai pas simplement créé une classe immuable; j'ai créé une classe variable qui dérive d'une classe immuable.

    Citation Envoyé par Chessmaster1966
    Tu fais erreur !!!

    Si tu arrives à modifier les données membres par la méthode Initialize() c'est parce qu'elles sont des variables toute variable est modifiable.
    Mon exemple est une réponse à la question de gl: "qu'est ce qui empêche ici de faire une fonction Display() qui modifie l'objet ?" Eh bien, ce qui l'empêche, c'est que Display() n'a accès aux membres de données que par des accesseurs virtuels qui les retournent par valeur. La différence entre Display() et Initialize(), c'est que cette dernière peut accéder aux membres de données directement, et non Display(). Je démontre donc qu'on peut imposer des contraintes d'immutabilité par encapsulation, plutôt que par mot-clé const.

    Concernant ton exemple avec getX(), je disais justement dans le message que tu citais: "modifier l'objet dans les getters [est] une erreur très évidente - à ce titre, [on] pourrait aussi bien faire des const_cast pour contourner const". Je suis bien d'accord que les erreurs sont courantes en programmation, mais il faut voir à trouver un certain équilibre. On pourrait très bien déclarer par erreur un membre "mutable", et oui ça arrive, et ça brise les garanties d'immutabilité sans le compilateur proteste. Donc, const n'est pas non plus une panacée contre la bêtise humaine.

    La classe A est élégante, n'est-ce pas ?
    Elle ne compile pas, parce que SetA est const.

    La "mutabilité" permet de contourner le "const" d'une fonction c'est juste un moyen élégant de contournement
    Mutable est un mot-clé ridicule dans un langage où tout est mutable par défaut. Il brise le contrat d'immutabilité d'une classe fournit par const (on n'aurait pas ce problème avec une vraie encapsulation comme j'ai illustré). Il est difficile de bien s'en servir et il devient trop souvent la porte de sortie à un épineux problème sémantique qui ne se résoud soit que par la dé-constification d'une grande section de code, soit par l'ajout de ce mot-clé, et les contraintes de temps sur le développement logiciel étant ce qu'elle sont, c'est la solution la plus courte qui prévaut bien souvent. On se retrouve avec 40000 mot-clés const et pas la moindre garantie d'immutabilité qui vaille. Est-ce que ça en vaut la peine? À vous de juger.

    Mais si tu as fais cette identification, rajouter des const là où il faut devient quasi-immédiat et un utilisateur de ton code ne pourra pas (*) appeler une fonction qui ne modifie pas l'objet sans recevoir un avertissement (une erreur) du compilo, ce qui est quand même bien plus "fort" (dans le sens se contourne moins vite) qu'un commentaire dans un code ou qu'une documentation de l'interface de ta classe.
    Rajouter des const est plus rapide maintenant, mais plus long à long terme, const se propageant à tout ce qu'il touche. De plus, définir des interfaces est plus fort, puisqu'il n'existe pas deux mot-clés pour les contourner (mutable et const_cast).

    Dans mon exemple, rajouter des const serait entièrement superflu. L'immutabilité est déjà contrainte. La méthode Display() ne peut modifier l'objet quand même bien le programmeur dormirait au gaz en tapant.

  8. #28
    Membre régulier

    Inscrit en
    Octobre 2010
    Messages
    50
    Détails du profil
    Informations forums :
    Inscription : Octobre 2010
    Messages : 50
    Points : 70
    Points
    70
    Par défaut
    Citation Envoyé par yan Voir le message
    De plus je vois pas l'intérêt d'avoir une classe immuable qui ne me donne que des accésseurs
    Pour faire une parenthèse: en C++, c'est rarement utilisé car comme on n'a pas de gestion de mémoire automatique, on évite de créer des tas d'objets temporaires. Mais dans des langages fonctionnels comme F#, ou même dans des langages impératifs sur plate-forme gérée comme C#, c'est un patron courant. La seule manière de "modifier" un objet est alors d'en créer un autre. Les types immuables sont souvent considérés comme une pièce cruciale du puzzle de la programmation parallèle, car ils éliminent totalement le problème des accès simultanés.

    Voir ici si vous savez lire l'anglais, je n'arrive pas à trouver un bon article en français.

    Bien sûr, encore une fois, le type que j'ai créé ici n'était pas immuable, mais bien variable avec interface immuable (voir réponse précédente).

  9. #29
    Membre chevronné
    Avatar de Joel F
    Homme Profil pro
    Chercheur en informatique
    Inscrit en
    Septembre 2002
    Messages
    918
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 44
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Chercheur en informatique
    Secteur : Service public

    Informations forums :
    Inscription : Septembre 2002
    Messages : 918
    Points : 1 921
    Points
    1 921
    Par défaut
    Citation Envoyé par Dr Dédé Voir le message
    Tiens, je l'attendais depuis un bout celle-là.

    On croirait que je blesse certaines personnes, à voir le nombre de "désapprobations" que mes messages reçoivent. Est-il si dur d'accepter que certains ont un point de vue différent? Je n'ai dit que des choses que je pouvais argumenter clairement et que j'ai illustrées ouvertement. Même si j'ai peut-être tort, ce que je ne crois pas, je crois avoir une discussion intéressante ici que j'ai rarement l'occasion d'avoir. Je doute que vous ayez souvent remis en question le bien fondé du const-correctness, et tiens, je vous donne l'occasion de le faire.
    je semi-déconne :o

    Plus sérieusement, je suis tout pour l'argumentation ici. Mais pour l'instant, je n'ai pas trouvé tes exemples fulgurants même si le rational derrière le truc avec l'interface semblait prometteur.

  10. #30
    screetch
    Invité(e)
    Par défaut
    en equipe ca ne vaut pas grand chose car comme ce sont des fonctions virtuelles je peux les redefinir dans une sous classe et d'un seul coup elles pourraient changer l'objet

    de plus j'ai du mal a comprendre comment tu peux dire d'un coter que const alourdit l'interface, et de l'autre creer des fonctions virtuelles de partout (parce que virtual par exemple, c'est plus long que const) la ou il n'y a aucun lieu d'en avoir

    Rien que par exemple, tu parles de "MonTypeReadOnly" alors que "const MonType" c'est plus court (meme avec l'espace) et pour 90% des gens c'est plus clair.

    Sans vouloir t'offenser, tu as un boulot qui te demande de faire du C++? tu travailles en equipe? tu as deja presenté ce concept en equipe? qu'en ont ils pensé?

  11. #31
    screetch
    Invité(e)
    Par défaut
    Citation Envoyé par Dr Dédé Voir le message
    Pour faire une parenthèse: en C++, c'est rarement utilisé car comme on n'a pas de gestion de mémoire automatique, on évite de créer des tas d'objets temporaires.
    ouais euh bof, la je veux bien quelques stats et preuves car ca me parait sorti de n'importe ou. Donc il va falloir argumenter un peu, ou restreindre la generalité

  12. #32
    Membre chevronné
    Avatar de poukill
    Profil pro
    Inscrit en
    Février 2006
    Messages
    2 155
    Détails du profil
    Informations personnelles :
    Âge : 40
    Localisation : France

    Informations forums :
    Inscription : Février 2006
    Messages : 2 155
    Points : 2 107
    Points
    2 107
    Par défaut
    Pour mettre un peu d'eau dans le moulin en faveur du const, je dirai qu'il fait parti des choses que j'utilise souvent et qu'il ne nuit pas à la lecture où la compréhension d'une fonction. Au contraire, il est plus précis. Je m'explique.

    Pour faire un parallèle simple, prenons les mathématiques. Beaucoup trouvent les maths rebutent parce que les formules sont "violentes" et hyper compliquées. Voici un estimateur classique du traitement du signal : le filtrage de Kalman


    avec
    : matrice qui relie l'état précédent k-1 à l'état actuel k
    : entrée de commande
    : matrice qui relie l'entrée de commande u à l'état x
    : matrice d'estimation a priori de la covariance de l'erreur
    : matrice d'estimation a posteriori de la covariance de l'erreur
    : matrice de covariance du bruit de process

    Passons sur la signification, ça n'a que peu d'intérêt ici. Ce que je veux dire, c'est que beaucoup de personnes bloquent sur la "représentation" et vont dire que c'est compliqué, qu'on ne comprend rien. Non, c'est faux. C'est juste précis. En mathématiques, tout est spécifié, rien n'est laissé au hasard. Tous les termes utilisés doivent être définis clairement, sans quoi tout tombe à l'eau.

    Pour moi, en programmation, c'est pareil. Le const est là pour spécifier un peu plus la fonction en lui donnant un rôle précis. Ceux qui pensent que ça allourdit l'interface, c'est qu'ils n'ont pas le niveau de compréhension requis pour s'abstraire de la pseudo lourdeur et profiter de la précision supplémentaire !

  13. #33
    Membre régulier Avatar de Chessmaster1966
    Inscrit en
    Juillet 2010
    Messages
    63
    Détails du profil
    Informations forums :
    Inscription : Juillet 2010
    Messages : 63
    Points : 74
    Points
    74
    Par défaut
    Elle ne compile pas, parce que SetA est const.
    Ca, je le sais.

    Mutable est un mot-clé ridicule dans un langage où tout est mutable par défaut. Il brise le contrat d'immutabilité d'une classe fournit par const
    Là je suis d'accord.

    (on n'aurait pas ce problème avec une vraie encapsulation comme j'ai illustré).
    Là je ne suis plus d'accord.
    Comme tu l'as illustré c'est que ta classe n'est pas une "immutable".
    Dans la définition des "getters" dans la classe enfant tu peux tu faire l'erreur d'appeler une fonction qui modifie l'objet et si tu t'en rends pas compte alors tu as un problème. Alors que si tu place les "const" aux "getters" tu règle tout problème de modification par erreur au moment de la compilation. Ton exemple n'est pas solide du point de vue de la conception.
    Si les auteurs du langage ont inventé un "const" pour des fonctions membres c'est bien pour ce que je viens de démontrer.

    J'ai repris ton exemple pour illustrer :

    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
     
    class MyTypeReadOnly {
    protected:
        virtual int getX() = 0;
        virtual float getF()  = 0;
    public:
        // La classe n'a que des getters, donc impossible de modifier l'objet
        void Display() { cout << getX() << " " << getF() << endl; }
    };
     
    class MyType : public MyTypeReadOnly {
        int m_x;
        float m_f;
    protected:
     
        int getX() { return m_x; }
        float getF()  { Initialize(); return m_f; } //Un bug, par inadvertance !
    public:
        // La classe a accès à ses membres de données, donc elle peut le modifier
        void Initialize() { m_x = 0; m_f = 0.0f; }
    };
    Alors que là :

    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
     
    class MyTypeReadOnly {
    protected:
        virtual int getX() = 0;
        virtual float getF()  = 0;
    public:
        // La classe n'a que des getters, donc impossible de modifier l'objet
        void Display() { cout << getX() << " " << getF() << endl; }
    };
     
    class MyType : public MyTypeReadOnly {
        int m_x;
        float m_f;
    protected:
        int getX() { return m_x; }
        float getF() const {  Initialize(); return m_f; } //Erreur de compilation.
    public:
        // La classe a accès à ses membres de données, donc elle peut le modifier
        void Initialize() { m_x = 0; m_f = 0.0f; }
    };
    Donc en faisant ce que tu as fait, tu n'est pas à l'abri de ce genre de problème. Alors que c'est juste un bout de code mais imagine que tu développe un énorme projet alors là bonjour les dégâts. Vas-tu créer des classes à qui en veut pour éviter d'utiliser des "const". Utiliser "const" c'est bien plus "safe" et en plus c'est élégant.




    On se retrouve avec 40000 mot-clés const et pas la moindre garantie d'immutabilité qui vaille. Est-ce que ça en vaut la peine? À vous de juger.
    Si justement, en utilisant "const" tu as la garantie qu'aucune modification ne sera faite par cette fonction et cela sera réglé à la compilation si tu essayes de faire le contraire le compilo t'arrêteras.

    Rajouter des const est plus rapide maintenant, mais plus long à long terme, const se propageant à tout ce qu'il touche. De plus, définir des interfaces est plus fort, puisqu'il n'existe pas deux mot-clés pour les contourner (mutable et const_cast).
    Si tu utilise les mots clés "mutable" et "const_cast" tu fait un choix délibérer de rompre le contrat d'une méthode "const" alors là tu assumes t'es responsabilités.

    Dans mon exemple, rajouter des const serait entièrement superflu. L'immutabilité est déjà contrainte. La méthode Display() ne peut modifier l'objet quand même bien le programmeur dormirait au gaz en tapant.
    Effectivement, "Display()" ne peut pas modifier les données membres mais les "getters" eux il peuvent comme je l'ai démontré plus haut.
    Le bonheur est sans raison

  14. #34
    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 screetch Voir le message
    de plus j'ai du mal a comprendre comment tu peux dire d'un coter que const alourdit l'interface, et de l'autre creer des fonctions virtuelles de partout (parce que virtual par exemple, c'est plus long que const) la ou il n'y a aucun lieu d'en avoir

    Rien que par exemple, tu parles de "MonTypeReadOnly" alors que "const MonType" c'est plus court (meme avec l'espace) et pour 90% des gens c'est plus clair.
    Le point remonté par Dr Dédé au sujet de l'interface ne concerne pas le nombre de caractères à saisir pour déclarer une fonction (qui au passage est une mesure que je ne trouve pas des plus pertinente, mais passons ce n'est pas très imortant) maus le nombre de fonctions qui compose l'interface. Et là effectivement, le const-correctness impose de doubler certaines fonctions (une version non const et une version const).

    Personellement je ne trouve pas ça rédhibitoire (essentiellement parce que dans le type de code sur lequel je travaille c'est somme toute assez peu fréquent et limité à des fonctions de très faible taille qui ne changent que rarement) mais je comprends l'argument.

  15. #35
    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 Chessmaster1966 Voir le message
    La "mutabilité" permet de contourner le "const" d'une fonction c'est juste un moyen élégant de contournement mais honêtement je n'en vois pas l'utilité si ce n'est que (peut-être) dans certains cas et encore.
    L'intérêt de mutable est de pouvoir rendre modifiables des membres qui sont purement techniques et ne participent à la constance sémantique d'un objet.
    Ce qui correspond typiquement aux mécanismes de cache, d'évaluation paresseuse, etc. La mise à jour de ces membres ne change pas la valeur ni l'état publique de l'objet.

  16. #36
    yan
    yan est déconnecté
    Rédacteur
    Avatar de yan
    Homme Profil pro
    Ingénieur expert
    Inscrit en
    Mars 2004
    Messages
    10 033
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France, Ille et Vilaine (Bretagne)

    Informations professionnelles :
    Activité : Ingénieur expert
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Mars 2004
    Messages : 10 033
    Points : 13 968
    Points
    13 968
    Par défaut
    Citation Envoyé par Dr Dédé Voir le message
    Pour faire une parenthèse: en C++, c'est rarement utilisé car comme on n'a pas de gestion de mémoire automatique, on évite de créer des tas d'objets temporaires. Mais dans des langages fonctionnels comme F#, ou même dans des langages impératifs sur plate-forme gérée comme C#, c'est un patron courant. La seule manière de "modifier" un objet est alors d'en créer un autre. Les types immuables sont souvent considérés comme une pièce cruciale du puzzle de la programmation parallèle, car ils éliminent totalement le problème des accès simultanés.

    Voir ici si vous savez lire l'anglais, je n'arrive pas à trouver un bon article en français.

    Bien sûr, encore une fois, le type que j'ai créé ici n'était pas immuable, mais bien variable avec interface immuable (voir réponse précédente).
    Merci pour le lien mais je n'ai pas dit qu'une classe immuable c'est le mal. Une classe immuable et const sont deux choses différentes et ne permettent pas les même chose.

    Ton exemple n'est qu'à base d’accesseur et de fonction qui utilise uniquement ces accesseurs. Du coup comment réimplémenter Display() dans un enfant?

    En terme de complexité, au lieu d'avoir 1 classe avec quelques const, tu doit maintenir 1 interface et 1 classe.

    D’ailleurs es ce que quelqu'un sait pourquoi JAVA (et C#?) n'ont pas ajouté un équivalent à const?

    [edit]
    http://www.javamex.com/java_equivale...nst_java.shtml
    As noted in the comments, a difference is that an attempt to access the unmodifiable object will be caught at runtime rather than compile time (as is the case with the const keyword).
    ca me rend perplexe...

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

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 617
    Points : 30 639
    Points
    30 639
    Par défaut
    Citation Envoyé par Dr Dédé Voir le message
    Je ne suis pas sûr que tu aies compris mon exemple. L'interface MyTypeReadOnly donne accès immuable à une classe variable, MyType. Quand tu passes un MyType*, tu donnes plein accès avec possibilité de modification. Quand tu passes la même instance en tant que MyTypeReadOnly*, tu ne donnes accès qu'aux méthodes qui garantissent de ne pas modifier la classe. C'est la même chose que const: quand tu passes un T*, tu donnes accès à toutes les méthodes, et quand tu passes un const T*, tu ne donnes accès qu'aux méthodes const. Sauf qu'au lieu d'avoir les méthodes const et non-const dans la même déclaration de classe, tu les sépare en deux déclarations, la variable héritant de l'immuable. Les fonctions qui ne doivent pas modifier l'objet peuvent être définies dans l'immuable, garantissant ainsi qu'elles ne modifient rien. Du coup, plus besoin de const.
    Si j e comprend ton point de vue, je ne peux pas l'accepter.

    Déjà parce que cela te fait multiplier les interfaces et les classes et que cela finit par devenir contre-productif en complexifiant tes hiérarchies à outrance.

    Imaginons, en effet, une première classe A, basée sur ton concept.

    Elle sera, logiquement, séparée en une interface "ImmuableA" qui présente les fonctions "ne modifiant pas l'objet" et une classe A qui hérite de ImmuableA et qui expose également les fonctions permettant de modifier l'objet.

    Si tu as, d'un autre coté, une classe B, tu lui fera suivre un raisonnement identique, puis, si tu as une classe C, aussi.

    Tu te retrouve donc avec 6 classes (car les interfaces ne sont que des classes "particulières" ne présentant que des fonctions membres ) là où... trois auraient suffit.

    Imaginons enfin que tu veuille faire dériver une classe Z de A et de de B, tu sera sans doute parti pour deux classes de plus, s'il y a des fonctions qui ne modifient pas l'objet qui ne sont présentes ni dans A ni dans B.

    La deuxième raison pour laquelle je ne peux pas être d'accord avec ton raisonnement, c'est parce que cela implique que tu aies un contrôle total et complet sur l'ensemble des classes qui interviennent dans une hiérarchie donnée:

    Tu ne pourras garantir qu'une fonction "complexe" de Z ne va pas modifier l'objet qu'en pouvant garantir que les fonctions qu'elles utilisent, et qui sont issues de A ou de B ne modifient pas les parties correspondantes.

    Tant que cela reste du domaine de responsabilité de ton équipe, tu peux arriver à garder ce contrôle, mais ce sera au prix d'une attention de tous les instants... sans doute au dépends de choses qui devraient parfois avoir la priorité en terme d'attention qu'on leur porte.

    Mais surtout, si, un peu plus tard, "quelqu'un" ne faisant pas forcément partie de ton équipe doit faire dériver une classe de A, de B, de C ou de Z, tu ne pourra pas avoir la certitude qu'il ne mélange pas allègrement les fonctions qui ne modifient pas les objet avec celles qui le font dans une fonction qui n'est pas sensée modifier l'objet final.

    En comparaison, lorsque tu pars sur le principe de respecter la const-correctness depuis le départ, et que tu déclare explicitement les fonctions ne devant pas modifier l'objet comme étant constantes, tu as beaucoup plus facile à apporter ce genre d'assurance, tant à ton équipe qu'à une personne extérieure.

    La raison est simple: le compilateur refusera que tu fasse quoi que ce soit qui revienne à modifier un objet que tu lui aura dit de considérer comme constant, du moins, sans avoir dit explicitement que tu voulais effectivement pouvoir apporter cette modification.

    Tu obtiens certainement le même résultat au final, mais tu gagne énormément du simple fait que tu peux porter ton attention sur autre chose de "plus important", simplement parce que tu sais que, si tu fait une boulette au niveau de la const-correctness, le compilateur sera toujours là pour te le faire remarquer
    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

  18. #38
    Membre chevronné Avatar de Astraya
    Homme Profil pro
    Consommateur de café
    Inscrit en
    Mai 2007
    Messages
    1 044
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 38
    Localisation : France

    Informations professionnelles :
    Activité : Consommateur de café
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Mai 2007
    Messages : 1 044
    Points : 2 239
    Points
    2 239
    Par défaut
    Perso, le mot clé "const" pour moi est à l'égal des mots clés public, protected et private, il rajoute un plus au principe d'encapsulation.

    mutable n'est pas un mot clé fait dans le but de casser le const. C'est fait dans le but d'avoir 2 méthodes, une version "const", une non "const", et de pouvoir utilisé une variable modifiable dans d'autres fonctions de la classe, dans la fonction qualifié "const" on peux la lire et la modifié oui, c'est sur, mais après on est un programmeur averti qui ne fais pas n'importe quoi ou on ne l'est pas et on fais n'importe quoi .
    Homer J. Simpson


  19. #39
    Membre régulier Avatar de Chessmaster1966
    Inscrit en
    Juillet 2010
    Messages
    63
    Détails du profil
    Informations forums :
    Inscription : Juillet 2010
    Messages : 63
    Points : 74
    Points
    74
    Par défaut
    mutable n'est pas un mot clé fait dans le but de casser le const. C'est fait dans le but d'avoir 2 méthodes,
    une version "const", une non "const", et de pouvoir utilisé une variable modifiable dans
    d'autres fonctions de la classe, dans la fonction qualifié "const" on peux la lire et la modifié oui,
    c'est sur, mais après on est un programmeur averti qui ne fais pas n'importe quoi ou on ne l'est pas et on fais n'importe quoi
    Le mot clé « mutable » permet de rompre le contrat d’ « immutabilité »
    d’une fonction « const » et non de créer deux méthodes l’une « const » et l’autre « non-const »
    mais « mutable » et bien non ce mot clé à été inventé pour ce que je dit !!!
    Si tu crée deux fonctions l’une « const » et l’autre « non-const » et à cette dernière tu lui affuble
    le mot clé « mutable », ce qui n’a aucun sens étant donné que par défaut toute zone mémoire est « mutable » !

    @ gl :
    L'intérêt de mutable est de pouvoir rendre modifiables des membres qui sont purement
    techniques et ne participent à la constance sémantique d'un objet. Ce qui correspond typiquement aux mécanismes
    de cache, d'évaluation paresseuse, etc. La mise à jour de ces membres ne change pas la valeur
    ni l'état publique de l'objet.
    Je n’ai jamais dit ce que tu as dit !
    « mutable » permet de casser le contrat de non modification par une fonction « const ». Je vais te le montrer
    par l'exemple ci-dessous :
    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 A
    {
            double a;
            double b;
     
            public:
                mutable double c;
                A(double number1, double number2) : a(number1), b(number2){}
    };
    int main()
    {
     //On rend l'objet "a" immutable", mais seul la donnée membre
     //"c" peut être modifiée par ce que on l'a déclarée "mutable" et le contrat constant pour cette donnée est rompu.
     const A a(1,2);
     a.c = 30;
     return EXIT_SUCCESS;
    }
    Alors si par défaut tout est "mutable" en C++ le mot clé "mutable" permet justement de faire ce que je viens d'exposer, il
    n'a de raison d'être que pour cela.
    Et je retire ce que j'ai dit en réponse à Dr Dédé lorsque je confirme que ce mot clé est ridicule. Et bien non !!!
    Imaginez que vous vouliez rendre inaccessible en écriture toute données membres sauf certaines sans le mot clé "mutable"
    ce cas ne peut pas être appliqué. Voilà donc pourquoi il a été inventé pour C++. Il permet la simplification et permet une meilleure
    maintenance que de créer des classes qui n'apportent aucune garantie quant à l'écrasement des données !!!

    Et pour finir sur « const » koala01 à parfaitement raison et suis en phase avec lui.

    Pour en revenir à "const_cast" pour supprimer toute "immutabilité" est un choix délibéré et de plus il requiert un
    pointeur. Un "const_cast" permet d'annuler effet d'un "const" en effet si tu as un pointeur non constant sur une zone
    constante (const int* ci) et que tu veuilles modifier la zone non constante à l'origine pointée par ci tu devras utiliser
    "const_cast" comme ceci :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
     int i = 40;
     const int* pci = &i;
     //*pci = 50; //Erreur: le pointeur ne peut pas modifier i puisque qu'il est supposé pointé sur un const.
     int* pi = const_cast<int*>(pci); //On convertit un pointeur vers un const en un pointeur vers un non-const.
     *pi = 60; //No problem !!!
    Mais si effectivement i est vraiment constant alors tu ne pourras pas la modifier encore moins avec un "const_cast" qui
    n'a pas cette vocation.
    Le bonheur est sans raison

  20. #40
    En attente de confirmation mail

    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Août 2004
    Messages
    1 391
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 33
    Localisation : France, Doubs (Franche Comté)

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

    Informations forums :
    Inscription : Août 2004
    Messages : 1 391
    Points : 3 311
    Points
    3 311
    Par défaut
    @Chessmaster1966: Tu expliques ce que fait mutable, gl t'as donné sa raison d'être : indiquer que certaines variable ne participes pas à l'état "publique" d'un objet : ie que leur modification n'influe pas sur la vision qu'un utilisateur extérieur aura de l'objet. Ce qui signifie qu'en pratique une variable mutable d'un objet const pourra quand même être modifié car const ne fait qu'indiquer que l'objet est immuable pour les utilisateurs. Ce qui implique que mutable ne rompt aucun contrat.

Discussions similaires

  1. Intérêt de mot clef const dans une méthode
    Par teddyalbina dans le forum C#
    Réponses: 3
    Dernier message: 05/03/2012, 14h22
  2. question sur le mot clef const
    Par elmcherqui dans le forum C++
    Réponses: 3
    Dernier message: 08/07/2008, 08h42
  3. Réponses: 14
    Dernier message: 25/10/2007, 15h00
  4. [Debat] le mot-clef "friend", est-ce si "mal"?
    Par 5:35pm dans le forum C++
    Réponses: 42
    Dernier message: 23/08/2007, 19h54

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