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 :

Plusieurs const dans le prototype d'une fonction


Sujet :

C++

  1. #1
    Membre à l'essai
    Profil pro
    Inscrit en
    Mars 2009
    Messages
    15
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2009
    Messages : 15
    Points : 13
    Points
    13
    Par défaut Plusieurs const dans le prototype d'une fonction
    Bonjour, dans le code ci-dessous, au niveau de la ligne...
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    const ChatDeGouttiere * const FonctionDeux(const ChatDeGouttiere * const leChat);
    ... j'ai compris que le troisième const sert à empêcher de modifier un membre de l'objet leChat, mais par contre, je ne vois pas à quoi pourrait servir les 3 autres const. Mais peut-être qu'ils ne servent pas dans ce cas précis.

    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
    #include <cstdlib>
    #include <iostream>
     
    using namespace std;
     
    class ChatDeGouttiere
    {
        public:
            ChatDeGouttiere();
            ChatDeGouttiere(ChatDeGouttiere &);
            ~ChatDeGouttiere();
     
            int LireAge() const { return wAge; }
            int DefAge(int age) { wAge = age; }
     
        private:
            int wAge;
    };
     
    const ChatDeGouttiere * const FonctionDeux(const ChatDeGouttiere * const leChat);
    //const ChatDeGouttiere * const FonctionDeux(ChatDeGouttiere * const leChat);
     
    int main(int argc, char *argv[])
    {
        system("PAUSE");
        return EXIT_SUCCESS;
    }
     
    const ChatDeGouttiere * const FonctionDeux(const ChatDeGouttiere * const leChat) // ne compile pas : leChat est constant
    //const ChatDeGouttiere * const FonctionDeux(ChatDeGouttiere * const leChat) // compile avec leChat->DefAge(8);
    {
        leChat->DefAge(8);
        return leChat;
    }
    Merci de m'éclairer.

  2. #2
    Rédacteur
    Avatar de 3DArchi
    Profil pro
    Inscrit en
    Juin 2008
    Messages
    7 634
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2008
    Messages : 7 634
    Points : 13 017
    Points
    13 017
    Par défaut
    Salut,
    En gros la réponse est dans la F.A.Q. : Quelle est la différence entre char*, const char* et char const * ?

  3. #3
    Expert éminent sénior
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 381
    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 381
    Points : 41 582
    Points
    41 582
    Par défaut
    Bonjour,
    1. Interdiction de modifier l'objet pointé par le pointeur retourné .
    2. Je n'ai jamais compris à quoi ça servait (const sur une valeur de retour). C'est un temporaire non-nommé, il y a donc déjà pas mal de choses qu'on n'a pas le droit de faire dessus...
    3. Interdiction de modifier l'objet pointé par le pointeur leChat
    4. Interdiction de modifier le pointeur leChat dans FonctionDeux (même sans le const, ça ne le modifierait pas dans la fonction appelante).

  4. #4
    Membre à l'essai
    Profil pro
    Inscrit en
    Mars 2009
    Messages
    15
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2009
    Messages : 15
    Points : 13
    Points
    13
    Par défaut
    Merci pour ces réponses, je commence à comprendre.
    Par contre, je n'arrive toujours pas à saisir à quoi sert le 2ème const dans le prototype de la fonction "FonctionDeux".
    Pour simplifier le code, j'ai supprimé les const que j'ai compris.
    J'ai modifié le code pour essayer de voir quel pointeur serait constant, mais je n'ai rien trouvé de constant... D'après ce que j'ai compris, ça sera le pointeur retourné par la fonction "FonctionDeux" qui devrait être constant, sauf qu'avec ce code, je peux modifier l'adresse pointée par le pointeur, donc il n'est pas constant.
    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
    #include <iostream>
     
    using namespace std;
     
    class ChatDeGouttiere
    {
        public:
            ChatDeGouttiere::ChatDeGouttiere();
            int LireAge() const { return wAge; }
            int DefAge(int age) { wAge = age; }
     
        private:
            int wAge;
    };
     
    ChatDeGouttiere::ChatDeGouttiere()
    {
        wAge = 2;
    }
     
    //
    // A quoi sert le const dans cette fonction ?
    //
    ChatDeGouttiere * const FonctionDeux(ChatDeGouttiere * leChat);
     
    int main(int argc, char *argv[])
    {
        ChatDeGouttiere Mistigri;
        ChatDeGouttiere Grosminet;
        ChatDeGouttiere * chat = FonctionDeux(&Mistigri);
     
        chat->DefAge(5);
        cout << chat->LireAge() << endl;
        chat = &Grosminet; // le pointeur n'est pas constant puisque ça marche
        chat->DefAge(6);
        cout << chat->LireAge() << endl;
     
        system("PAUSE");
        return EXIT_SUCCESS;
    }
     
    ChatDeGouttiere * const FonctionDeux(ChatDeGouttiere * leChat)
    {
        leChat->DefAge(4);
        cout << leChat->LireAge() << endl;
        ChatDeGouttiere Felix;
        leChat = &Felix;
        cout << leChat->LireAge() << endl;
        return leChat;
    }

  5. #5
    Membre confirmé
    Inscrit en
    Août 2004
    Messages
    556
    Détails du profil
    Informations forums :
    Inscription : Août 2004
    Messages : 556
    Points : 588
    Points
    588
    Par défaut
    Citation Envoyé par o_r_a_x Voir le message
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
        ChatDeGouttiere * chat = FonctionDeux(&Mistigri);
        chat = &Grosminet; // le pointeur n'est pas constant puisque ça marche
    Là tu modifie la variable "chat" qui est de type ChatDeGouttiere* et non ChatDeGouttier*const.

    La code suivant ne compilera pas:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    ChatDeGouttiere *const chat = FonctionDeux(&Mistigri);
    chat = &Grosminet;
    Ce code compilera:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    const ChatDeGouttiere *chat = FonctionDeux(&Mistigri);
    chat = &Grosminet;
    Mais pas celui-là:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    const ChatDeGouttiere *chat = FonctionDeux(&Mistigri);
    chat.DefAge(1);
    Tu vois la nuance ?

    const se réfère à ce qui le précède, s'il n'y a rien, à ce qui le suit.

    const X veut dire que X est constant
    X const Y veut également dire que X est constant mais pas Y.
    X Y const veut dire que Y est constant et X non constant.

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

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 629
    Points : 30 692
    Points
    30 692
    Par défaut
    Salut,

    Il faut déjà comprendre ce qu'est un pointeur pour arriver à comprendre cette histoire de const type * const...

    En effet, un mointeur n'est ni plus ni moins... qu'une variable qui a cela de spécial de contenir l'adresse mémoire à laquelle on trouvera une donnée particulière.

    Bon, d'accord, c'est en fait un peu plus complexe que cela, mais, cette "définition" succincte reste tout à fait juste et sera malgré tout suffisante pour te permettre de comprendre.

    Comme toute variable, tu peux envisager de modifier un pointeur (je parle du pointeur, et non de la variable qui se trouve à l'emplacement de la mémoire représenté par la valeur du pointeur )

    Tu peux, entre autres, appliquer toute une arithmétique sur les pointeurs, en décidant de l'incrémenter, de le décrémenter, d'y additionner ou d'en soustraire une valeur et même, bien que ce ne soit surement pas conseillé, décider de le multiplier ou de le diviser par une valeur quelconque.

    Le premier const dans un code proche de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    const UnType * const /*...*/
    représente en réalité la mise en oeuvre d'une règle particulière, car, selon la norme, const s'applique normalement à ce qui le précède, sauf si c'est le premier terme d'une expression, auquel cas, il s'applique à ce qui suit.

    ce code, en appliquant la règle générale au lieu de la règle particulière (la partie "sauf si" de la règle) s'écrirait donc sous la forme de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    UnType const * const/*...*/
    Le premier const, donc indique
    Tu peux aller voir du coté de l'objet vers lequel je pointe, mais attention: regarder, pas toucher...
    ou, si tu préfères, indique que tu ne peux pas modifier l'objet vers lequel pointe le pointeur.

    Le deuxième const s'applique, lui, à ce qui le précède, vu que l'on est dans la règle générale.

    Ce qui précède, c'est... le pointeur (en fait, la variable qui contient l'adresse mémoire à laquelle se trouve l'objet), et le const indique donc... que tu ne peux pas modifier l'adresse qu'il contient.

    Pour t'aider à comprendre, imaginons un code proche de
    Le premier const te permet donc un code proche de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    const int * ptr;
    /* ptr pointe vers var1 */
    ptr=&var1;
    /* et maintenant, il pointe vers var2 */
    ptr=&var2;
    /* mais je ne peux pas modifier var2 */
    ++(*ptr); //refusé: var2 est considéré comme constant */
    Par contre, le deuxième const indique que le pointeur pointera toujours vèrs la même adresse mémoire...

    Cela sous entend qu'il faut penser à définir correctement cette adresse mémoire au moment où l'on déclare le pointeur:
    /* ca, c'est autorisé, et ptr2 pointe donc vers var1 */
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    int * const ptr2=&var1;
    /* on a même le droit de modifier var1 */
    ++(*ptr2);
    /* par contre, on ne peut pas dédider de faire pointer ptr2 sur var2 */
    ptr2=&var2; /*refusé... on en peut pas changer l'adresse contenue par ptr2
    Donc, si on met les deux const ensemble, sous une forme proche de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    const int * const ptr3=&var1;
    ou de (histoire de suivre la règle générale plutôt que l'exception, même si, au final, cela revient strictement au même)
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    int const * const ptr4=&var1;
    tu obtiens un pointeur constant nommé ptr3 (respectivement ptr4) vers une variable constante de type entier (pointant tous les deux vers... var1, qui ne peut être modifiée).

    Les deux lignes suivantes seront donc refusées à la compilation:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    /* n'essaye pas, tu te fera jeter par le compilateur */
    ptr3=&var2; // on a dit que le pointeur était constant
    --(*ptr4); // on a dit que la variable était consante
    j'espère que maintenant, les choses seront claires

  7. #7
    Membre à l'essai
    Profil pro
    Inscrit en
    Mars 2009
    Messages
    15
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2009
    Messages : 15
    Points : 13
    Points
    13
    Par défaut
    Je pense avoir compris la règle pour le const, je me suis peut-être mal fait comprendre. C'est dans le prototype (si on appelle bien ça comme ça... ) de la fonction que je ne comprends pas.

    Prenons un exemple :
    Ici le pointeur est constant donc je ne peux pas le modifier l'adresse pointée.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    ChatDeGouttiere * FonctionDeux(ChatDeGouttiere * const leChat)
    {
        ChatDeGouttiere Felix;
        leChat = &Felix; // impossible puisque le pointeur est constant (on est d'accord ?)
        return leChat;
    }


    Mais dans ce code ci-dessous (j'ai changé le const), qu'est-ce qui est constant ? le pointeur retourné par la fonction ? C'est ça que je ne comprends pas.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    ChatDeGouttiere * const FonctionDeux(ChatDeGouttiere * leChat)
    {
        ChatDeGouttiere Felix;
        leChat = &Felix;
        return leChat;
    }

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

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 629
    Points : 30 692
    Points
    30 692
    Par défaut
    Citation Envoyé par o_r_a_x Voir le message
    Je pense avoir compris la règle pour le const, je me suis peut-être mal fait comprendre. C'est dans le prototype (si on appelle bien ça comme ça... ) de la fonction que je ne comprends pas.

    Prenons un exemple :
    Ici le pointeur est constant donc je ne peux pas le modifier l'adresse pointée.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    ChatDeGouttiere * FonctionDeux(ChatDeGouttiere * const leChat)
    {
        ChatDeGouttiere Felix;
        leChat = &Felix; // impossible puisque le pointeur est constant (on est d'accord ?)
        return leChat;
    }
    On est bien d'accord, et, en plus, tu ne peux pas renvoyer un pointeur sous forme non constante s'il était, à l'origine, constant...

    En effet, la constance d'un objet (qu'il s'agisse d'un pointeur ou d'une variable "normale") apporte des restrictions quant à l'usage que tu peux faire de cet objet.

    Tu peux donc décider à tout moment de transformer un objet non constant en un objet constant (ou appeler un fonction membre constante au départ d'un objet non constant), mais pas le contraire, ou du moins, pas de manière directe (il faut passer par un const_cast), car cela revient à lever des restrictions mises à la base.

    Et, quoi qu'il arrive, si tu en viens à vouloir lever les restrictions imposées par la constance d'un objet, il est peut être temps de t'interroger sur les raisons qui t'avaient incité à le rendre consant
    Mais dans ce code ci-dessous (j'ai changé le const), qu'est-ce qui est constant ? le pointeur retourné par la fonction ? C'est ça que je ne comprends pas.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    ChatDeGouttiere * const FonctionDeux(ChatDeGouttiere * leChat)
    {
        ChatDeGouttiere Felix;
        leChat = &Felix;
        return leChat;
    }
    Le pointeur renvoyé est constant...

    Que tu pourra, malgré tout, envisager de récupérer au travers d'un pointeur non constant (parce que rien ne t'empeche d'assigner l'adresse d'un pointeur constant à un pointeur non constant )

    Ceci dit, un tel code posera potentiellement deux problèmes:

    Si tu décide de passer un pointeur (non constant) sur une variable (non constante) de type leChat à une fonction, c'est pour deux raisons:

    Soit, tu veux que la fonction soit en mesure de modifier la variable, soit, tu passe un pointeur parce qu'il s'agit... d'une variable dont la mémoire est gérée de manière dynamique (qui a été allouée avec new ou new[])...

    Dans le deuxième cas, si tu modifie "comme cela" l'adresse, et surtout si tu invoque la fonction sous une forme proche de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    ChatDeGouttiere * felix = new ChatDeGouttiere;
    felix=FonctionDeux(felix);
    Tu te trouve confronté à une fuite mémoire, qui mènera fatalement à terme à des catastrophes.

    Le deuxième problème est encore bien pire

    En effet, l'objet pointé par le pointeur est détruit au moment où l'on quitte la fonction...

    Cela signifie que ton pointeur pointe... vers une adresse qui ne contient plus (ou qui risque de contenir très rapidement tout autre chose)... un ChatDeGouttiere

    Tant que tu te contentera de simples accès "en lecture" de l'objet, disons que tu t'en sortira (avec un peu de chance) avec des résultats aberrants... ou tu lancera un missile dans le désert de Goby

    Par contre, dés que tu voudra accéder à ton ChatDeGouttiere pour y modifier des valeurs, tu peux être sur que cela tournera à la catastrophe...

  9. #9
    Membre à l'essai
    Profil pro
    Inscrit en
    Mars 2009
    Messages
    15
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2009
    Messages : 15
    Points : 13
    Points
    13
    Par défaut
    Citation Envoyé par koala01 Voir le message
    Le pointeur renvoyé est constant...

    Que tu pourra, malgré tout, envisager de récupérer au travers d'un pointeur non constant (parce que rien ne t'empeche d'assigner l'adresse d'un pointeur constant à un pointeur non constant )
    Oui, c'est ce que je fais en faisant ça je pense :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    ChatDeGouttiere Mistigri;
    ChatDeGouttiere Grosminet;
    ChatDeGouttiere * chat = FonctionDeux(&Mistigri);
    chat = &Grosminet;
    Donc en fait, le const dans la fonction :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    ChatDeGouttiere * const FonctionDeux(ChatDeGouttiere * leChat)
    ne sert pas à grand chose puisque rien ne m'oblige à le récupérer dans un pointeur constant.


    Il faudrait que j'écrive :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    ChatDeGouttiere * const chat = FonctionDeux(&Mistigri);
    pour que le pointeur chat soit "réellement" constant.

  10. #10
    Membre confirmé
    Inscrit en
    Août 2004
    Messages
    556
    Détails du profil
    Informations forums :
    Inscription : Août 2004
    Messages : 556
    Points : 588
    Points
    588
    Par défaut
    Le fait que ta fonction renvoit un pointeur constant ou non constant ne change en effet rien, étant donné qu'une fonction est une rvalue.

    C'est un peu comme les fonctions qui renvoient const int et non int. Ca change rien.

    Par contre, pour ce qui est des références, c'est autre chose.

    n'est strictement pas pareil que Mais là, le const ne s'applique pas au type de retour (qui est simplement une référence), mais sur l'objet lui même.

    En fait, T*const func() ne sert pas à grand chose, car prenons le code suivant:
    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
    #include <iostream>
     
    struct A {};
     
    class B {
    	A* a;
     
    public:
    	B() 
    	{
    		a = new A();
    	}
     
    	B( const B& o ) :
    		a( new A(*o.a) ) 
    	{
     
    	}
     
    	~B() {
    		delete a;
    	}
     
    	A* getA() const {
    		return a;
    	}
    };
     
    int main()
    {
    	B b;
    	std::cout << b.getA() << std::endl;
     
    	b.getA() = new A(); // erreur ! b.getA() n'est pas une l-value
    	std::cout << b.getA() << std::endl;
        return 0;
    }

  11. #11
    Expert éminent sénior
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 381
    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 381
    Points : 41 582
    Points
    41 582
    Par défaut
    JulienDuSud est le seul ici qui ait donné une réponse intéressante.

    On avait tous les deux déjà compris pour les variables: Il n'y a que pour le type de retour qu'on ne comprenait pas...

  12. #12
    screetch
    Invité(e)
    Par défaut
    ouais zut j'arrive apres la bataille, mais tout comme JulienDuSud, le const en question ne sert a rien.

  13. #13
    Membre à l'essai
    Profil pro
    Inscrit en
    Mars 2009
    Messages
    15
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2009
    Messages : 15
    Points : 13
    Points
    13
    Par défaut
    Et bien merci pour toutes ces réponses, j'y vois déjà plus clair avec les const.

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Réponses: 4
    Dernier message: 19/05/2006, 10h26
  2. Réponses: 3
    Dernier message: 09/03/2006, 15h12
  3. Pause dans l'exécution d'une fonction
    Par FrankOVD dans le forum Général JavaScript
    Réponses: 2
    Dernier message: 29/06/2005, 07h48
  4. Plusieurs SELECT dans l'ouverture d'une connection
    Par pmboutteau dans le forum ASP
    Réponses: 6
    Dernier message: 01/04/2005, 11h09
  5. Récupérer le prototype d'une fonction
    Par uaz dans le forum Général Python
    Réponses: 2
    Dernier message: 27/07/2004, 17h24

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