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 :

fonction:passage par valeur ou référence


Sujet :

C++

  1. #1
    Membre très actif
    Homme Profil pro
    retraité
    Inscrit en
    Septembre 2006
    Messages
    286
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 84
    Localisation : France, Indre et Loire (Centre)

    Informations professionnelles :
    Activité : retraité

    Informations forums :
    Inscription : Septembre 2006
    Messages : 286
    Par défaut fonction:passage par valeur ou référence
    bonjour à tous,
    La fonction FcIntStr,dont code ci-dessous, ne répond pas à mon attente.
    Je voudrais une sortie sous les lignes Ch ou CA de préférence à celle de St.
    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
     
     
    //essai 
    //#include <string>
    #include <iostream>
    #include <sstream>  
    //#include <fstream>
     
    using namespace std;
     
    string FcIntStr(int NbA,string ChA,int fcvue)
    {//29/12/11/22h
    //IntVerStr=FcIntStr(nb,ch,fcvue); 
         ostringstream ossNbA;
         ossNbA<<NbA;
         ChA=ossNbA.str();
    return ChA;      
    }//29/12/11/22h
     
    int main()
    {   
        int fcvue=0;
        cout<<"essai int vers string"<<endl; 
        int nb=15;
        string Ch;
        string ChA;
        string IntVerStr;
     
        IntVerStr=FcIntStr(nb,Ch,fcvue);
     
        cout<<"St "<<IntVerStr<<endl;
        cout<<"It "<<nb <<endl;
        cout<<"CA "<<ChA<<"*"<<endl;//pourquoi vide?  
        cout<<"Ch "<<Ch <<"*"<<endl;//pourquoi vide?
     
        cout<<"<E>";cin.get();
    }
    La fonction doit être mal écrite()?
    Merci pour cette étude.

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

    Informations forums :
    Inscription : Juin 2008
    Messages : 7 634
    Par défaut
    Salut,
    ChA est vide car elle n'est pas initialisé autrement qu'à la construction. Ne pas confondre ChA dans la fonction main et ChA dans la fonction FcIntStr. Bien qu'elles aient le même nom, ce sont bien deux variables différentes car sises dans des 'portées' (~blocs) différents.

    Ch est vide car la fonction FcIntStr prend son argument par valeur. Cela signifie qu'il fait une copie de l'argument avant d'entrer dans la fonction. Toute modification dans la fonction se faisant sur la copie, cela n'aura pas d'impact sur l'argument passé en paramètre. Il faudrait utiliser un passage par référence si tu voulais modifier l'argument :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    string FcIntStr(int NbA,string &ChA,int fcvue)
    {//29/12/11/22h
    //IntVerStr=FcIntStr(nb,ch,fcvue);
         ostringstream ossNbA;
         ossNbA<<NbA;
         ChA=ossNbA.str();
    return ChA;
    }//29/12/11/22h

  3. #3
    Membre très actif
    Homme Profil pro
    retraité
    Inscrit en
    Septembre 2006
    Messages
    286
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 84
    Localisation : France, Indre et Loire (Centre)

    Informations professionnelles :
    Activité : retraité

    Informations forums :
    Inscription : Septembre 2006
    Messages : 286
    Par défaut
    Bonjour et merci pour ce petit cours de C++/dev-cpp.
    J'ai d'autres fonctions du même tonneauJe vais les transformer avec le
    dopant "&".
    Merci beaucoup(..et rapide!)

  4. #4
    Expert éminent
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 644
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 53
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 644
    Par défaut
    Salut,

    En fait, ta fonction renvoie une chaine de caractères et je ne vois donc pas pourquoi tu voudrais que la chaine de caractères passée en argument soit modifiée

    Je ne dis pas que ce n'est pas juste que de faire en sorte que la chaine de caractères passée en argument soit modifiée, car cela peut avoir un sens, mais, ce que je dis, c'est que le nom de ta fonction et celui des paramètres n'est pas suffisamment bien choisi pour nous permettre de nous faire une idée de l'opportunité qu'il peut y avoir à ce que ce soit le cas

    Je m'explique:

    La logique que tu places dans ta fonction est sensée modifier ChA et renvoyer ChA sous la forme de valeur, mais, est-ce vraiment utile

    En effet, si tu récupères la chaine renvoyée par ta fonction dans une autre variable que celle qui est passée comme étant ChA, tu auras deux variables qui auront exactement la même valeur : la variable passée en tant que paramètre et celle qui aura récupéré le retour de la fonction...

    Qu'est ce qui pourrait justifier ce fait

    Tu as, en effet, deux solutions:

    Soit, tu te dis que tu veux modifier une variable qui existe dans la fonction appelante (cela peut avoir un sens, s'il est question de concaténer des données ) et, à ce moment là, tu n'as pas besoin de la valeur de retour, avec un code proche de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
     
    void foo(int NbA,string &ChA)
    {
        std:::stringstream ss;
        ss<<NbA<<ChA;
        ChA == ss.str();
    }
    int main()
    {
        std::string truc="machin";
        int basard = 10;
        foo(basard, truc);
        /* truc="10machin" ;) */
    }
    Soit tu te dis que, ce qui t'intéresse, c'est le retour de ta fonction:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    std::string bar(int NbA,std::string const &ChA) // le fait de passer la chaine
                                         // sous la forme d'une référence constante évite
                                         // la copie de la chaine, mais empêche qu'elle soit
                                         // modifiée
    {
        std:::stringstream ss;
        ss<<NbA<<ChA;
        return ss.str();
    }
    et tu peux alors décider soit de récupérer le résultat dans une autre variable, soit de le récupérer dans une variable existante:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    int main()
    {
        std::string truc="truc";
        int basard = 10;
        truc=bar(10,truc); // oui oui, ca marche :D : truc = "10truc"
        /* OU OU OU OU */
        std::string brol="brol";
        int bidule = 20;
        std::string recup=bar(bidule, brol);
        /* brol = "brol", recup = "20brol" */
        /*...*/ 
        return 0;
    }
    Par contre, le fait de mélanger les deux est, très certainement, le meilleur moyen d'avoir un "effet de bord" aux effets des plus désagréables et difficiles à retrouver...

    Imagine un peu les fonctions
    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
    std::string bar(int i, std::string & str)
    {
        std:::stringstream ss;
        ss<<NbA<<str;
        str== ss.str();
        return str;
    }
    void foo(std::string & str)
    {
        int i = 10;
        /*... */
        std::string temp = bar(i, str);
        /* ici, on travaille avec temp  ;) */
    }
    int main()
    {
        std::string truc="truc";
        /* 15 instructions */
        foo(truc);
        /* 15 instructions */
       /* je voudrais que truc vaille "10truc" :D */
       bar(10,truc);
       std::cout<<truc<<std::endl; //Mais pourquoi truc, qui est sensée valoir
                                   // "10truc" vaut elle "1010truc" ????
       return 0;
    }
    Ici, le cas est relativement simple, et il apparaitra (relativement) vite que truc vaut déjà "10truc" bien avant que tu n'appelles bar() dans main() (à cause de l'appel à foo() ), mais c'est typiquement le genre de choses, lorsque tu as des fonctions qui appellent des fonctions qui appellent des fonctions qu'il te sera très difficile de repérer, surtout si tes fonctions sont un tant soit peu complexes

    Moralité : évites toi bien des soucis et évite qu'une valeur de retour soit identique à la nouvelle valeur d'un argument passé en entrée / sortie
    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

  5. #5
    Membre très actif
    Homme Profil pro
    retraité
    Inscrit en
    Septembre 2006
    Messages
    286
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 84
    Localisation : France, Indre et Loire (Centre)

    Informations professionnelles :
    Activité : retraité

    Informations forums :
    Inscription : Septembre 2006
    Messages : 286
    Par défaut
    Merci pour ces hautes et logiques considérations qui ont une grande valeur.
    Le & ajouté à la "variable" sort me suffit.Je vais veiller à la construction des noms des variables.
    Bien noter que j'ai modifié sort en sortie car sort est un mot réservé....tri en français.
    Merci à tous.

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

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 644
    Par défaut
    As-tu seulement compris tout ce que ce petit "&" implique et le sens de mon intervention

    Mon intervention avait pour but de te faire prendre conscience que tu est de toute évidence face à un problème de conception dés le moment où tu envisage de faire en sorte qu'une variable passée en argument soit modifiée d'un coté tout en récupérant le résultat de cette modification par la valeur de retour de la fonction!!!

    Comme l'indiquaient les portions de code que j'ai fournies (et surtout les commentaires que j'ai pris la peine de rajouter ), tu risques vraiment de te retrouver avec des valeurs qui peuvent te sembler incohérentes, simplement parce que l'appel d'une fonction aura eu pour résultat d'appeler une fonction qui apportera des modifications auxquelles tu ne penses peut etre pas

    Le fait qu'une fonction modifie une variable qui lui est passée en argument est ce que l'on appelle couramment un "effet de bord" et il s'agit de se méfier comme de la peste de ces derniers, parce qu'il est particulièrement difficile d'avoir un aperçu clair et précis de la manière dont il va se répercuter dans le code

    De plus, le caractère "&" n'est pas un caractère magique intervenant dans une quelconque pratique vaudou!!

    C'est le symbole qui, utilisé sous la forme présentée ici, indique que l'on travaille avec une référence sur un objet.

    Le fait de travailler avec des références présente énormément d'avantages, mais nécessite aussi d'aborder les choses avec la plus grande discipline possible:

    Du fait que l'on travaille en réalité avec un alias de l'objet référencé, il faut être conscient que tout ce qui arrive à la référence arrivera en réalité à l'objet référencé et que l'idéal reste donc de toujours éviter les effets de bord en déclarant constant tout ce qui peut l'être, justement pour éviter qu'une modification n'aille prendre effet sur quelque chose que l'on n'imagine peut etre pas

    Je ne peux donc que t'inciter à méditer sur ce que je viens d'écrire et à prendre en compte ces remarques, meme si c'est sur un "petit projet", ne serait ce que pour t'habituer directement à faire du travail correct
    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

  7. #7
    Membre très actif
    Homme Profil pro
    retraité
    Inscrit en
    Septembre 2006
    Messages
    286
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 84
    Localisation : France, Indre et Loire (Centre)

    Informations professionnelles :
    Activité : retraité

    Informations forums :
    Inscription : Septembre 2006
    Messages : 286
    Par défaut
    Merci pour ce complément de cours/philosophie.
    Le passage par valeur grâce à & (signe vaudou?) me va très bien.Je me suis habitué à surveiller les valeurs d'entrées,ce qui se passe dans une fonction et ce qui en sort depuis toujours.
    Tout va bien pour moi.
    Merci pour cette année.

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

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 644
    Par défaut
    Citation Envoyé par senvedgi Voir le message
    Merci pour ce complément de cours/philosophie.
    Le passage par valeur grâce à & (signe vaudou?)
    Ce n'est pas par valeur, c'est par référence, on a dit
    Je me suis habitué à surveiller les valeurs d'entrées,ce qui se passe dans une fonction et ce qui en sort depuis toujours.
    Justement, tu pourrais t'éviter énormément de soucis et de controle en utilisant une politique connue sous le nom de const correctness:

    Quitte à transmettre une variable par référence (par exemple pour en éviter la copie qui peut demander énormément de temps et de ressources), tranmet la sous la forme d'une référence constante si cette variable n'a pas vocation à être modifiée et déclare toutes les fonctions membres de tes classes n'ayant pas vocation à modifier l'état de ta classe constante.

    Le compilateur sera beaucoup plus têtu que toi et refusera systématiquement toute tentative de modification
    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

  9. #9
    Membre très actif
    Homme Profil pro
    retraité
    Inscrit en
    Septembre 2006
    Messages
    286
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 84
    Localisation : France, Indre et Loire (Centre)

    Informations professionnelles :
    Activité : retraité

    Informations forums :
    Inscription : Septembre 2006
    Messages : 286
    Par défaut
    Avant de répondre j'ai parcouru des forhumes(c'est la saison) pour faire le tri
    et tout le monde a l'air de dire(je ne suis qu'un enfant de choeur au Vatican) que c'était un passage par valeur:donc je n'avais rien compris ni ici ou ni là!
    Du monde d'où je viens on écrit:
    1/FcMachin(strABC,intXYZ)
    et on appelle
    2/entréechaine="chchch";
    3/www=FcMachin(entréechaine,sortienombre)
    4/sortienombre=3,14116+1(!!)
    C'est la position dans les parenthèses en 1 et 3 qui fonctionne.EN cas de mauvaise écriture plouf!
    C'est du passage par référence pour moi.
    Merci!
    Bonne année.

  10. #10
    Expert éminent
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 644
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 53
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 644
    Par défaut Petit cours express sur les arguments de fonctions
    Bon, reprenons...

    Il existe, en C++, trois possibilités pour passer une variable en argument à une fonction:
    1. Par valeur : en utilisant uniquement le type de la variable qui sera passée et en fournissant le nom pour l'argument (ex: void foo(Type value) )
    2. Par référence : en insérant le symbole & (qui est le symbole qui indique que l'on veut utiliser une référence sur un objet) après le nom de type, et avant le nom de l'argument (ex void bar( Type & reference ) )
    3. Par pointeur : en insérant le symbole * (qui est le symbole qui indique que l'on utilise un pointeur) après le nom du type et avant le nom de l'argument (ex : void truc(Type * pointer ) )
    Lorsque l'on transmet la variable par valeur, il y a copie de celle-ci au sein de la fonction appelée.

    Il n'y a donc aucune relation entre les modifications apportée au sein de la fonction appelée et la variable qui a été transmise dans la fonction appelante, et ce, meme si le nom de l'argument et le nom de la variable qui a été transmise sont les mêmes

    Par exemple, le code
    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
     
    #include <iostream>
    void foo(int value)
    {
        value *=10;
        std::cout<<"dans foo() : value = "<<value<<std::endl;
    }
    int main()
    {
        int value = 15;
        std::cout<<"avant foo() : value ="<<value<<std::endl;
        foo( value );
        std::cout<<"apres foo() : value = "<<value<<std::endl;
        return 0;
    }
    donnera la sortie
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    avant foo() : value = 15
    dans foo() : value = 150
    apres foo() : value = 15
    Lorsque l'on transmet la variable par référence, on transmet en réalité un alias de la variable: Il n'y a pas de copie de la variable transmise et, même si c'est l'argument porte un autre nom que la variable d'origine, tout ce qui arrive à l'argument dans la fonction appelée est répercuté sur la variable dans la fonction appelante:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    void bar( int & reference) // le & indique que l'on utilise une référence
    {
        reference*=10;
        std::cout<<"dans bar() : reference= "<<reference<<std::endl;
    }
     
    int main()
    {
        int value = 15;
        std::cout<<"avant bar() : value ="<<value<<std::endl;
        bar( value );
        std::cout<<"apres bar() : value = "<<value<<std::endl;
        return 0;
    }
    donnera la sortie
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    avant bar() : value = 15
    dans bar() : reference = 150
    apres bar() : value = 150
    avec le passage par pointeur, on transmet l'adresse mémoire à laquelle se trouve un objet du type est indiqué.

    Comme c'est une adresse, il y a copie de l'adresse mémoire à laquelle l'objet se trouve, mais il n'y a pas copie de l'objet en lui-même.

    La grosse différence qu'il y a entre le passage d'argument par référence et le passage d'argument par pointeur tient dans le fait qu'une référence apporte une garantie de non nullité (en dehors du fait qu'elle utilise la même syntaxe que l'objet lui-même pour accéder à son contenu ) : Lorsque l'on transmet une référence sur un objet, l'objet en question doit exister, alors que l'on peut transmettre une adresse mémoire connue comme étant invalide (NULL ou, en C++11, nullptr) lorsque la fonction attend un pointeur.

    Cependant, si on accède à "ce qui est pointé" par le pointeur (à condition qu'il pointe vers une adresse valide, évidemment ) tout ce qui arrive à "ce qui est pointé" par le pointeur dans la fonction appelée arrive également ( fatalement ) à la variable dans la fonction appelante.

    Je passe volontairement une grande partie d'explications sur les pointeurs, tu n'auras qu'à relire un tuto ou un livre pour savoir de quoi il s'agit (mais saches néanmoins que les pointeurs présentent une série d'inconvénients qui font que l'on préfère généralement le passage par référence au passage par pointeur à moins que l'on n'ait vraiment pas le choix )

    Ainsi, le code
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    void bar( int * pointer) // le * indique que l'on utilise un pointeur
    {
        *pointer += 10; // le * indique que l'on accède à "ce qui est pointé" par pointer
        std::cout<<"dans bar() : *pointer = "<<*pointer<<std::endl; //idem
    }
     
    int main()
    {
        int value = 15;
        std::cout<<"avant bar() : value ="<<value<<std::endl;
        bar( &value ); // le & indique que l'on prend l'adresse mémoire à laquelle se trouve value
        std::cout<<"apres bar() : value = "<<value<<std::endl;
        return 0;
    }
    donnera la sortie
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    avant bar() : value = 15
    dans bar() : *pointer = 25
    apres bar() : value = 25
    Pour être complet, il existe une quatrième possibilité, qui n'est en définitive qu'une particularité du passage par référence: le passage par référence constante.

    Il est en effet possible d'indiquer au compilateur qu'il doit considérer une variable (ou une référence sur une variable) comme étant constante en rajoutant le mot clé const après le nom du type: Type const myConstant; ou void bidule(Type const & MyConstantReference).

    nota: d'après la norme, le mot clé const s'applique à ce qui se trouve à sa gauche sauf s'il n'y a rien à sa gauche, auquel cas il s'applique alors à ce qui se trouve à sa droite :

    Type const myConstant; est donc strictement pareil à const Type myConstant; et void bidule(Type const & MyConstantReference) est strictement pareil à void bidule(const Type & MyConstantReference), bien que les premières versions respectent la règle générale et que les deuxièmes profitent de l'exception qui confirme la règle


    L'avantage de travailler avec des objets constants (ou des références sur des objets constant) tient dans le fait que le compilateur refusera toute instruction qui risque de modifier l'objet (ou l'objet référencé) en question:

    Si tu travailles avec des structures ou des classes (car c'est strictement la meme chose en C++, mis à part la visibilité par défaut des membre ), seules les fonctions membre déclarées constantes (comprend: s'étant engagées à ne pas modifier l'objet) pourront être appelées depuis l'objet constant (ou la référence constante vers un objet)

    Par contre, il est tout à fait possible d'invoquer une fonction s'étant engagée à ne pas modifier l'objet depuis un objet non constant (ou une référence constante vers un objet).

    Ainsi, si tu as une classe proche de
    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 MyClass
    {
        /* le constructeur de MyClass */
        MyClass(int value) : value(value){}
        /* une fonction qui s'engage à ne pas modifier l'objet */
        void print() const
        {
            std::cout<< "value :"<<std::endl;
        }
        /* et une fonction qui ne s'y engage pas */
        void multiply(int factor)
        {
            value *= factor;
        }
        private:
        /* le membre qui nous intéresse */
        int value;
    };
    tu pourras invoquer MyClass::multiply et la fonction MyClass::print depuis une fonction qui aura pris un objet de type MyClass par valeur ou depuis une fonction qui aura pris un objet de type MyClass par référence (non constante) mais tu ne pourra invoquer que la fonction MyClass::print dans une fonction qui aura pris un objet de type MyClass sous la forme d'une référence constante
    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
     
    void foo(MyClass value)
    {
        value.multiply(10); // ca marche :D
        std::cout<< "dans foo() value::";
        value.print(); // ca marche aussi :D
    }
    void bar(MyClass & reference)
    {
        value.multiply(10); // ca marche :D
        std::cout<< "dans bar() reference::";
        value.print(); // ca marche aussi :D
    }
    void truc(MyClass const & constreference)
    {
       /* cet appel sera refusé, si tu le décommente, tu auras une erreur
        * de compilation
        */
        // value.multiply(10);
        std::cout<< "dans truc() constreference::";
        // ca, par contre, ca marche :D
        value.print(); 
    }
    int main()
    {
        MyClass obj1(10);
        std::cout<<"avant foo() : obj1::";
        obj1.print();
        foo(obj1);
        std::cout<<"apres foo() : obj1::";
        obj1.print();
        std::cout<<std::endl;
     
        MyClass obj2(15);
        std::cout<<"avant bar() : obj2::";
        obj2.print();
        foo(obj2);
        std::cout<<"apres bar() : obj2::";
        obj2.print();
        std::cout<<std::endl;
     
     
        MyClass obj3(25);
        std::cout<<"avant truc() : obj3::";
        obj3.print();
        truc(obj3);
        std::cout<<"apres truc() : obj3::";
        obj3.print();
     
        return 0;
    }
    aura pour sortie
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    avant foo() : obj1::value = 10
    dans foo() : value::value = 100
    apres foo() : obj1::value = 10
     
    avant bar() : obj2::value = 15
    dans bar() : reference::value = 150
    apres bar() : obj2::value = 150
     
    avant truc() : obj3::value = 25
    dans truc() : constreference::value = 25
    apres truc() : obj3::value = 25
    Le passage par référence constante permet, en outre, d'utiliser ce que l'on appelle une variable temporaire anonyme dans la fonction appelée.

    Ainsi, nous pourrions très bien avoir un code proche de
    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
     
    void truc(MyClass const & constreference)
    {
       /* cet appel sera refusé, si tu le décommente, tu auras une erreur
        * de compilation
        */
        // value.multiply(10);
        std::cout<< "dans truc() constreference::";
        // ca, par contre, ca marche :D
        value.print(); 
    }
    int main()
    {
        truc(25);
        /* la variable qui été créée pour permettre l'appel de truc n'existe 
         * plus ici :D
         */
        return 0;
    }
    Comme il existe une possibilité de convertir un int en un objet de type MyClass (grace au constructeur de MyClass), nous pouvons créer une variable anonyme (c'est un objet de type MyClass pour lequel non n'avons pas de nom dans main() ) temporaire (qui n'existe que pour la durée de l'exécution de truc() ) qui sera utilisée dans truc.

    Cela ne peut se faire qu'avec le passage par référence constante , car la norme estime qu'il n'y a aucune raison de permettre de modifier la variable référencée par l'argument, étant donné que nous n'aurons aucun moyen d'y accéder dans la fonction appelante (AKA main() )une fois sorti de l'exécution de la fonction appelée (AKA truc() )

    Cela permet, entre autre, de respecter le principe qui conseille de créer les variables le plus près possible de l'endroit où nous en avons besoin tout en évitant d'avoir, par la suite, une variable qui ne servirait plus à rien parce qu'elle n'était utile que pour permettre l'appel de la fonction

    En espérant que cette prose t'aie permis d'enfin comprendre ce que l'on entendait par "passage par valeur", "passage par référence (constante)" ou "passage par pointeur", ainsi que l'utilisation qui peut être faite de ces possibilités
    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

  11. #11
    Membre très actif
    Homme Profil pro
    retraité
    Inscrit en
    Septembre 2006
    Messages
    286
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 84
    Localisation : France, Indre et Loire (Centre)

    Informations professionnelles :
    Activité : retraité

    Informations forums :
    Inscription : Septembre 2006
    Messages : 286
    Par défaut

    Il y a tout là dedans.
    Il doit rien y avoir à rajouter.
    Merci!

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

Discussions similaires

  1. Passage par valeur & passage par référence
    Par maiza_med dans le forum C++
    Réponses: 13
    Dernier message: 28/02/2015, 02h02
  2. fonction passage par valeur ,par adresse
    Par hybride11 dans le forum C
    Réponses: 2
    Dernier message: 21/08/2010, 18h25
  3. passage paramètre par valeur et référence
    Par new_wave dans le forum Débuter avec Java
    Réponses: 2
    Dernier message: 09/03/2008, 18h53
  4. Passage par Valeur
    Par xc78370 dans le forum Langage
    Réponses: 8
    Dernier message: 20/03/2006, 23h21
  5. Passage par valeur / passage par adresse
    Par jeje99 dans le forum C++
    Réponses: 13
    Dernier message: 16/02/2006, 10h29

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