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 :

Est-ce dans ce cas un constructeur par copie qui est appelé ?


Sujet :

C++

  1. #1
    Membre éprouvé
    Avatar de beegees
    Homme Profil pro
    Développeur Web
    Inscrit en
    Mars 2004
    Messages
    3 610
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 49
    Localisation : Belgique

    Informations professionnelles :
    Activité : Développeur Web
    Secteur : Enseignement

    Informations forums :
    Inscription : Mars 2004
    Messages : 3 610
    Points : 1 277
    Points
    1 277
    Par défaut Est-ce dans ce cas un constructeur par copie qui est appelé ?
    Bonjour tout le monde,

    Je voudrais juste savoir si ceci :


    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    m_TC.Ajouter(CCercle(CC.Champs(1),atof(CC.Champs(2))));
    vous fais penser à l'appel d'un constructeur par copie ?

    Merci d'avance pour votre aide.

    beegees

  2. #2
    Expert éminent
    Avatar de raptor70
    Inscrit en
    Septembre 2005
    Messages
    3 173
    Détails du profil
    Informations personnelles :
    Âge : 39

    Informations forums :
    Inscription : Septembre 2005
    Messages : 3 173
    Points : 6 812
    Points
    6 812
    Par défaut
    Citation Envoyé par beegees Voir le message
    Bonjour tout le monde,

    Je voudrais juste savoir si ceci :


    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    m_TC.Ajouter(CCercle(CC.Champs(1),atof(CC.Champs(2))));
    vous fais penser à l'appel d'un constructeur par copie ?

    Merci d'avance pour votre aide.

    beegees
    Tu est succeptible d'avoir une copie si ta methode "Ajouter" est déclaré comme ca :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    void TaClasse::Ajouter( CCercle cercle );
    pour passer par référence ( sans copie ) :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    void TaClasse::Ajouter( CCercle & cercle );

  3. #3
    Rédacteur/Modérateur
    Avatar de JolyLoic
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2004
    Messages
    5 463
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 50
    Localisation : France, Yvelines (Île de France)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Août 2004
    Messages : 5 463
    Points : 16 213
    Points
    16 213
    Par défaut
    Ca ne marchera pas, car l'objet créé est un temporaire, et on ne peut pas passer par référence un temporaire. Donc plutôt :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    void TaClasse::Ajouter( CCercle const & cercle );
    Maintenant, rien n'empêche le code dans ajouter de faire des copies. Si tu veux vraiment tester ça, pourquoi ne pas interdire la copie (constructeur par recopie privé) et voir ce que ça donne ?

  4. #4
    Expert éminent
    Avatar de raptor70
    Inscrit en
    Septembre 2005
    Messages
    3 173
    Détails du profil
    Informations personnelles :
    Âge : 39

    Informations forums :
    Inscription : Septembre 2005
    Messages : 3 173
    Points : 6 812
    Points
    6 812
    Par défaut
    Citation Envoyé par JolyLoic Voir le message
    Ca ne marchera pas, car l'objet créé est un temporaire, et on ne peut pas passer par référence un temporaire. Donc plutôt :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    void TaClasse::Ajouter( CCercle const & cercle );

  5. #5
    Membre éprouvé
    Avatar de beegees
    Homme Profil pro
    Développeur Web
    Inscrit en
    Mars 2004
    Messages
    3 610
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 49
    Localisation : Belgique

    Informations professionnelles :
    Activité : Développeur Web
    Secteur : Enseignement

    Informations forums :
    Inscription : Mars 2004
    Messages : 3 610
    Points : 1 277
    Points
    1 277
    Par défaut
    Citation Envoyé par JolyLoic Voir le message
    Ca ne marchera pas, car l'objet créé est un temporaire, et on ne peut pas passer par référence un temporaire. Donc plutôt :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    void TaClasse::Ajouter( CCercle const & cercle );
    Maintenant, rien n'empêche le code dans ajouter de faire des copies. Si tu veux vraiment tester ça, pourquoi ne pas interdire la copie (constructeur par recopie privé) et voir ce que ça donne ?
    Bonjour,

    Merci pour ta réponse.

    Comment vois-tu que s'est un objet temporaire ?

    Je pense plutôt que l'on passe par un constructeur spécifique ?

    merci.

    beegees

  6. #6
    Membre du Club
    Profil pro
    Inscrit en
    Mars 2004
    Messages
    76
    Détails du profil
    Informations personnelles :
    Âge : 42
    Localisation : France

    Informations forums :
    Inscription : Mars 2004
    Messages : 76
    Points : 56
    Points
    56
    Par défaut
    Citation Envoyé par beegees Voir le message
    Comment vois-tu que s'est un objet temporaire ?
    J'suis pas un expert en C++ mais j'dois pouvoir répondre.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    CCercle(CC.Champs(1),atof(CC.Champs(2))
    Le CCercle en question n'est pas enregistré dans une variable avant d'être passé à ta méthode.

    Enfin je crois... J'suis nul en C++.

  7. #7
    Membre éprouvé
    Avatar de beegees
    Homme Profil pro
    Développeur Web
    Inscrit en
    Mars 2004
    Messages
    3 610
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 49
    Localisation : Belgique

    Informations professionnelles :
    Activité : Développeur Web
    Secteur : Enseignement

    Informations forums :
    Inscription : Mars 2004
    Messages : 3 610
    Points : 1 277
    Points
    1 277
    Par défaut
    Citation Envoyé par Cyborg Voir le message
    J'suis pas un expert en C++ mais j'dois pouvoir répondre.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    CCercle(CC.Champs(1),atof(CC.Champs(2))
    Le CCercle en question n'est pas enregistré dans une variable avant d'être passé à ta méthode.

    Enfin je crois... J'suis nul en C++.
    Merci pour ta réponse.

    Comment, avec le peu de code que je t'ai donné, tu peux voir que CCercle n'est pas enregistré dans une variable ?

    Si ça peut te rassurer, je suis encore plus null que toi mais bon j'fais tout pour y remédier

    beegees

  8. #8
    Membre éclairé Avatar de befalimpertinent
    Profil pro
    Inscrit en
    Avril 2007
    Messages
    561
    Détails du profil
    Informations personnelles :
    Âge : 41
    Localisation : France, Gironde (Aquitaine)

    Informations forums :
    Inscription : Avril 2007
    Messages : 561
    Points : 833
    Points
    833
    Par défaut
    Citation Envoyé par beegees Voir le message
    Merci pour ta réponse.

    Comment, avec le peu de code que je t'ai donné, tu peux voir que CCercle n'est pas enregistré dans une variable ?

    Si ça peut te rassurer, je suis encore plus null que toi mais bon j'fais tout pour y remédier

    beegees
    Tout dépend de ce qu'est CCercle !
    Mais au vu de son nom il doit s'agir d'une classe non ?
    Donc au vue de la ligne fournie tu crées ton objet CCercle "à la volée". Autrement dis c'est un temporaire.

    Mais pour répondre à la question initiale montres nous le prototype de Ajouter

  9. #9
    Alp
    Alp est déconnecté
    Expert éminent sénior

    Avatar de Alp
    Homme Profil pro
    Inscrit en
    Juin 2005
    Messages
    8 575
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 35
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations forums :
    Inscription : Juin 2005
    Messages : 8 575
    Points : 11 861
    Points
    11 861
    Par défaut
    Un temporaire est une variable qui n'a pas de nom.
    C'est à dire que c'est une variable qui désigne quelque chose, mais que l'on identifie pas par un nom.

  10. #10
    Membre éprouvé
    Avatar de beegees
    Homme Profil pro
    Développeur Web
    Inscrit en
    Mars 2004
    Messages
    3 610
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 49
    Localisation : Belgique

    Informations professionnelles :
    Activité : Développeur Web
    Secteur : Enseignement

    Informations forums :
    Inscription : Mars 2004
    Messages : 3 610
    Points : 1 277
    Points
    1 277
    Par défaut
    Citation Envoyé par befalimpertinent Voir le message
    Tout dépend de ce qu'est CCercle !
    Mais au vu de son nom il doit s'agir d'une classe non ?
    Donc au vue de la ligne fournie tu crées ton objet CCercle "à la volée". Autrement dis c'est un temporaire.

    Mais pour répondre à la question initiale montres nous le prototype de Ajouter
    Salut,

    Je pense que s'est celui-ci

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    bool  Ajouter(const CRectangle& Modele);
    Merci pour tout.

    beegees

  11. #11
    Membre expérimenté
    Avatar de coyotte507
    Profil pro
    Inscrit en
    Octobre 2006
    Messages
    1 327
    Détails du profil
    Informations personnelles :
    Âge : 34
    Localisation : France

    Informations forums :
    Inscription : Octobre 2006
    Messages : 1 327
    Points : 1 452
    Points
    1 452
    Par défaut
    Salut,

    Je vais essayer d'être clair

    Dans cet exemple précis, tu passes ton objet par référence. Donc peu importe l'endroit où il est créé, lorsque tu passes ton objet en paramètre, tu obtiens l'objet lui-même, pas une copie.

    Donc il n'y a aucune raison pour qu'un quelconque constructeur soit appelé en plus.

    Dans ton exemple, cela fait que le seul constructeur appelé sera:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    CCercle::CCercle(const char* param1, float param2);
    Et il ne le sera qu'une fois!

    D'ailleurs, un exemple en 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
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    #include <iostream>
     
    using namespace std;
     
    class A
    {
      public:
        int i;
     
        //Constructeur par défaut
        A(int i) : i (i) {cout << "constructeur avec entier appele!" << endl;}
        //par Copie
        A(const A& Source) : i(Source.i) { cout << "Constructeur par copie appele!" << endl;}
     
        //La fonction ajouter qui t'intéresse:
        void ajouter(const A& item) { cout << "A::ajouter(const A& item)" << endl;}
    };
     
    int main()
    {
        //On crée d'abord la classe pour faire le test.
        //initialisation avec entier
        A objet(8);
     
        //Saut de ligne
        cout << endl;
     
        //Puis on appelle ta fonction:
        objet.ajouter(A(2));
        return 0;
    }
    Et quand on regarde le log, on voit qu'aucun constructeur par copie n'a été appelé à aucun moment.

    Et si le prototype avait été bool Ajouter(CRectangle Modele) ?

    Il y a deux cas possibles:
    1. Si tu crées l'objet dans ton appel à la fonction, comme tu le fais:
      Code : Sélectionner tout - Visualiser dans une fenêtre à part
      m_TC.Ajouter(CCercle(CC.Champs(1),atof(CC.Champs(2)));
      Alors l'objet est créé et passé tel quel à ta fonction, en effet il n'est pas utilisé en dehors alors pourquoi en faire une copie?
    2. Si tu crées l'objet avant:
      Code : Sélectionner tout - Visualiser dans une fenêtre à part
      1
      2
      3
      CCercle MonCercle(CC.Champs(1),atof(CC.Champs(2));
       
      m_TC.Ajouter(MonCercle);
      Alors là, par contre, on a besoin de passer une copie à la fonction Ajouter(), et donc le constructeur par copie de CCercle sera appelé


    D'ailleurs, pour ces deux derniers cas (qui ne concernent pas ton exemple), le code pour tester n'est modifié que très légèrement (par rapport à celui que j'ai donné plus haut).

    Voilà!

  12. #12
    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,

    Si tu veux être complet sur ce qui peut se passer lorsque tu dois fournir un paramètre à une fonction, il faut savoir qu'il peut se passer plein de choses différentes, qui se subdivisent ainsi:
    • Tu peux passer un simple alias d'une variable: la variable utilisée au sein de la fonction est vraiment celle qui est utilisée comme argument, éventuellement connue sous un autre nom
    • Tu peux observer la création d'une variable
      • Par copie
      • par conversion, celle-ci pouvant survenir
        • de manière implicite (sans que l'utilisateur ne doive préciser qu'il souhaite la conversion)
        • de manière explicite (l'utilisateur doit préciser qu'il souhaite la conversion, si c'est le cas
    • le compilateur sort sur une erreur
    Pour pouvoir déterminer précisément ce qui va se passer, il va falloir prendre plusieurs contextes en compte.

    Je vais d'abord en dresser la liste, puis j'expliquerai chacun des concepts, et enfin, j'en viendrai aux explications
    1. le fait que la variable qui sert d'argument existe (aie été déclarée dans la fonction appelante) avant l'appel de la fonction en ayant le bon type (ou un type dérivé) ou non
    2. Le fait que l'argument soit fourni sous forme de référence ou sous forme d'objet
    3. Le fait que la norme interdit les variables anonymes(temporaires) non constantes
    4. Les constructeurs existant pour le type de l'argument passé
    5. Le fait que l'un ou l'autre constructeur soit déclaré explicit.

    La première question à se poser consiste donc à déterminer si la variable qui sert d'argument existe déjà dans la fonction appelante.

    Cela signifie que c'est soit un argument qui a été passé à la fonction appelante, soit que la variable a été déclarée avant l'appel de la fonction, et bien sûr, le fait que la variable soit du bon type (c'est à dire, soit exactement le bon type, soit une classe dérivée du type attendu).

    La seconde question à se poser est la manière dont l'argument est passé à la fonction, et c'est le prototype de la fonction qui nous permet d'y répondre:

    nous avons un passage par objet si le prototype est du genre de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    type_de_retour laFonctionParObjet(type_argument argument);
    et nous avons un passage par référence si le prototype est du genre de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    type_de_retour laFonctionParReference(type_argument& argument);
    L'interdiction par la norme de créer une variable anonymes (temporaires) non constantes va influer directement sur notre choix de déclarer l'argument const ou non.

    Si la variable n'existe pas (ou risque de/peut ne pas exister) en ayant le bon type (ou un type qui dérive du type attendu) avant l'appel de la fonction, il y aura d'office création d'une variable temporaire lors de l'appel à la fonction.

    Dans ce cas, l'argument devra être déclaré constant, et le prototype devra donc prendre la forme de

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    type_de_retour laFonctionParObjetConstant(const type_argument argument);
    ou de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    type_de_retour laFonctionParReferenceConstante( const type_argument& argument);
    selon le cas

    On l'oublie souvent, mais un constructeur prenant un argument peut servir d'opérateur de conversion, servant à créer un élément du type de la classe dont on défini le constructeur au départ du type de l'argument que reçoit ce constructeur, et ce, quel que soit le type de l'argument (à l'exception de la classe dont on définit le constructeur, ca va de soi... vu qu'il prend alors le nom de constructeur par copie ).

    Par défaut, la conversion est implicite, ce qui signifie que l'utilisateur n'a aucun besoin de la demander pour qu'elle ait lieu.

    Ainsi, si tu as deux classes et une fonction sous une forme 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
    20
    21
    22
    23
    24
    class A
    {
        public:
            /* constructeur de la classe A, sans argument, et ne faisant rien
             */
            A(){}
    };
    class B
    {
        public:
            /* Constructeur de B prenant un A en argument,
             * sans s'inquiéter de savoir s'il est constant ou non, ou si c'est une  
             * référence ou non
             */
    };
    /* ici, je veux montrer la conversion, je sais donc que j'aurai une variable
     * temporaire, et il faut donc que l'argument soit constant
     * par contre, le fait qu'il s'agisse d'un objet ou d'une référence ne jouera pas
     * dans la démonstration ;)
     */
    void laFonction(const B b)
    {
        /*ce qu'il faut faire avec b*/
    }
    on pourrait très bien avoir le code suivant
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    int main()
    {
        A monA;
        laFonction(monA);//monA est implicitement converti en B au moment de l'appel
        return 0;
    }
    et cela fonctionnera sans aucun problème, grâce à la conversion implicite.

    On s'est rendu compte à l'usage, mais alors qu'il y avait déjà énormément de codes qui utilisaient cette possibilité, que ce genre de comportement peut représenter un danger dans certaines circonstances particulières...

    Il a donc été décidé de rajouter le mot clé explicit, à mettre devant le constructeur, de manière à permettre d'indiquer au compilateur qu'il ne doit effectuer la conversion que si l'utilisateur le demande explicitement.
    Ainsi, avec une classe C et une fonction laFonctionC définies sous la forme 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
     
    class C
    {
        public:
            /* Constructeur de C prenant un A en argument,
             * sans s'inquiéter de savoir s'il est constant ou non, ou si c'est une  
             * référence ou non
             */
            explicit C(A a){}
    };
    /* ici, je veux montrer la conversion, je sais donc que j'aurai une variable
     * temporaire, et il faut donc que l'argument soit constant
     * par contre, le fait qu'il s'agisse d'un objet ou d'une référence ne jouera pas
     * dans la démonstration ;)
     */
    void laFonction(const C c)
    {
        /*ce qu'il faut faire avec c*/
    }
    le code suivant sera refusé par le compilateur (parce que l'utilisateur ne demande pas explicitement de convertir le A en C)
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    int main()
    {
        A monA;
        laFonctionC(monA);//La conversion échoue car l'utilisateur ne dit pas
                           //explicitement qu'il veut l'effectuer
    }
    mais le code suivant fonctionnera, car l'utilisateur demande explicitement la conversion:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    int main()
    {
        A monA;
        laFonctionC(C(monA));//La conversion échoue car l'utilisateur ne dit pas
                             //explicitement qu'il veut l'effectuer
    }
    Au final, tu te rend compte que la réponse complète sur ce qui se passe quand tu passe un argument à une variable va être bien plus compliquée que de savoir s'il s'agit d'une copie ou non...

    Voici sans doute la meilleure manière de la présenter:

    • Si la variable du bon type ou d'un type dérivé existe
      • Si passage par référence : pas de construction: utilisation d'un alias
      • Si passage par objet : construction par copie
    • Si la variable du bon type ou d'un type dérivé n'existe pas, par référence comme par objet
      • Si argument non constant : echec
      • Si argument constant :
        • Si pas de constructeur adéquat pour l'argument :echec
        • Si constructeur adéquat
          • Si constructeur explicit
            • Si conversion demandée : construction par conversion
            • Si conversion non demandée : échec
          • Si pas constructeur explicit : construction par conversion

    Pfffiouuu... Voilà encore un post digne des annales ...

    Et encore, je n'ai pas parler des pointeurs...

    Sache que le pointeurs suivra exactement les mêmes règles que s'il s'agissait d'une variable tout à fait normale, simplement, le fait de prendre l'adresse d'une variable existante provoque la création du pointeur (et un pointeur est toujours un type primitif ayant un nombre de bits suffisant pour représenter au minimum toutes les adresses mémoires disponible) mais que l'objet pointé lui sera d'office l'équivalent d'un alias de variable

    [EDIT]Au fait, et pour m'assurer que tu comprenne bien le sens de la phrase du bon type ou d'un type dérivé (et similaire) utilisé dans tout ce texte, je parle vraiment de la relation d'héritage entre une classe de base et ses classes dérivées.

    Ainsi, si tu as un arbre d'héritage du genre 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
    class GrandMere
    {
        /*...*/
    };
    class Base : public GrandMere
    {
        /*...*/
    };
    class Derivee : public Base
    {
     
    };
    class Derivee2 : public Base
    {
     
    };
    et que ta fonction attend un élément de type Base (sous forme d'objet ou de référence), les objets de type Base, Derivee et Derivee2 (ainsi que les types qui héritent de l'une de ces trois classes) seront considérés comme étant du bon type.

    Par contre, les objets de type GrandMere ou qui héritent de GrandMere sans hériter de Base seront considérés comme étant d'un mauvais type

  13. #13
    Expert éminent
    Avatar de raptor70
    Inscrit en
    Septembre 2005
    Messages
    3 173
    Détails du profil
    Informations personnelles :
    Âge : 39

    Informations forums :
    Inscription : Septembre 2005
    Messages : 3 173
    Points : 6 812
    Points
    6 812
    Par défaut
    Citation Envoyé par koala01 Voir le message
    Salut,

    Si tu veux être complet sur ce qui peut se passer lorsque tu dois fournir un paramètre à une fonction, il faut savoir qu'il peut se passer plein de choses différentes, qui se subdivisent ainsi:

    ...

    Par contre, les objets de type GrandMere ou qui héritent de GrandMere sans hériter de Base seront considérés comme étant d'un mauvais type
    Ce serait bien comme item dans la ce mini article

  14. #14
    Provisoirement toléré
    Profil pro
    Inscrit en
    Février 2008
    Messages
    439
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2008
    Messages : 439
    Points : 495
    Points
    495
    Par défaut
    Citation Envoyé par Alp Voir le message
    Un temporaire est une variable qui n'a pas de nom.
    C'est à dire que c'est une variable qui désigne quelque chose, mais que l'on identifie pas par un nom.
    temporaire = objet temporaire.

    Une expression n'est jamais un temporaire (une expression n'est pas un objet). Mais l'évaluation d'une expression produit un temporaire : on dit alors que l'expression désigne un temporaire (sous entendu lors de son évaluation).

    Une variable a une déclaration, donc un nom. Le terme variable n'est pas à prendre au sens de ce qui peut varier : la valeur d'un objet temporaire peut varier, mais ne n'est pas une variable; le valeur d'une constante déclarée avec le type "const int" ne peut pas varier, mais c'est une variable.

    Une expression désigne un temporaire si c'est une r-valeur de type classe. Principalement, ce sont (Classe étant un type de classe) :
    • l'appel d'une fonction ne renvoyant pas une référence
    • la construction d'un temporaire : Classe (liste-d'arguments)
    • ou static_cast<Classe>(expr) ou Classe(expr) ou (Classe)expr
      (ces trois expressions sont équivalentes)

  15. #15
    Alp
    Alp est déconnecté
    Expert éminent sénior

    Avatar de Alp
    Homme Profil pro
    Inscrit en
    Juin 2005
    Messages
    8 575
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 35
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations forums :
    Inscription : Juin 2005
    Messages : 8 575
    Points : 11 861
    Points
    11 861
    Par défaut
    Tu as tout à fait raison. J'ai été trop vague. Je m'excuse envers le posteur original.

    Merci des précisions corrector.

  16. #16
    Membre éprouvé
    Avatar de beegees
    Homme Profil pro
    Développeur Web
    Inscrit en
    Mars 2004
    Messages
    3 610
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 49
    Localisation : Belgique

    Informations professionnelles :
    Activité : Développeur Web
    Secteur : Enseignement

    Informations forums :
    Inscription : Mars 2004
    Messages : 3 610
    Points : 1 277
    Points
    1 277
    Par défaut
    Salut,
    Salut Coyotte, désolé pour le retard de ma réponse.

    Je vais essayer d'être clair
    Avec moi, il vaut mieux

    Dans cet exemple précis, tu passes ton objet par référence. Donc peu importe l'endroit où il est créé, lorsque tu passes ton objet en paramètre, tu obtiens l'objet lui-même, pas une copie.
    OK merci, ça s'est important de le rappeler.

    Donc il n'y a aucune raison pour qu'un quelconque constructeur soit appelé en plus.
    ça par contre je ne savais pas mais s'est logique vue que l'on ne crée pas un nouvel objet. Donc si je passe un objet par copie il appelle le constructeur ?

    Dans ton exemple, cela fait que le seul constructeur appelé sera:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    CCercle::CCercle(const char* param1, float param2);
    Et il ne le sera qu'une fois!
    Donc on appelle le constructeur uen seule fois lors de la création de l'objet de type CCercle alors ?

    D'ailleurs, un exemple en 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
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    #include <iostream>
     
    using namespace std;
     
    class A
    {
      public:
        int i;
     
        //Constructeur par défaut
        A(int i) : i (i) {cout << "constructeur avec entier appele!" << endl;}
        //par Copie
        A(const A& Source) : i(Source.i) { cout << "Constructeur par copie appele!" << endl;}
     
        //La fonction ajouter qui t'intéresse:
        void ajouter(const A& item) { cout << "A::ajouter(const A& item)" << endl;}
    };
     
    int main()
    {
        //On crée d'abord la classe pour faire le test.
        //initialisation avec entier
        A objet(8);
     
        //Saut de ligne
        cout << endl;
     
        //Puis on appelle ta fonction:
        objet.ajouter(A(2));
        return 0;
    }
    Merci, je vais tester.
    Et quand on regarde le log, on voit qu'aucun constructeur par copie n'a été appelé à aucun moment.

    Et si le prototype avait été bool Ajouter(CRectangle Modele) ?

    Il y a deux cas possibles:
    1. Si tu crées l'objet dans ton appel à la fonction, comme tu le fais:
      Code : Sélectionner tout - Visualiser dans une fenêtre à part
      m_TC.Ajouter(CCercle(CC.Champs(1),atof(CC.Champs(2)));
      Alors l'objet est créé et passé tel quel à ta fonction, en effet il n'est pas utilisé en dehors alors pourquoi en faire une copie?
    2. Si tu crées l'objet avant:
      Code : Sélectionner tout - Visualiser dans une fenêtre à part
      1
      2
      3
      CCercle MonCercle(CC.Champs(1),atof(CC.Champs(2));
       
      m_TC.Ajouter(MonCercle);
      Alors là, par contre, on a besoin de passer une copie à la fonction Ajouter(), et donc le constructeur par copie de CCercle sera appelé


    D'ailleurs, pour ces deux derniers cas (qui ne concernent pas ton exemple), le code pour tester n'est modifié que très légèrement (par rapport à celui que j'ai donné plus haut).
    Bon si ça concerne pas mon cas, je vais pas trop les lire pour le moment afin de ne pas trop m'embrouiller.

    Voilà!
    Merci encore à toi, à Koala et aux autres pour votre aide qui est hyper utile, j'ai fais un grand bon en avant depuis deux semaines, je me sents bien plus à l'aise en C++ depuis ses deux dernières semaines.

    beegees

  17. #17
    Membre éprouvé
    Avatar de beegees
    Homme Profil pro
    Développeur Web
    Inscrit en
    Mars 2004
    Messages
    3 610
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 49
    Localisation : Belgique

    Informations professionnelles :
    Activité : Développeur Web
    Secteur : Enseignement

    Informations forums :
    Inscription : Mars 2004
    Messages : 3 610
    Points : 1 277
    Points
    1 277
    Par défaut
    Bonjour Koala,

    un super grand merci pour ta hyper géniale réponse.

    Je dois t'avouer que je n'y comprends pas tout mais bon, je vais encore le relire deux ou trois fois et puis ça devrait aller.

    Une chose que je sais, s'est que ta réponse a déjà sa place dans mon cours

    Tu peux passer un simple alias d'une variable: la variable utilisée au sein de la fonction est vraiment celle qui est utilisée comme argument, éventuellement connue sous un autre nom
    Saurais-tu me dire ce que tu entends pas alias ?

    Comme je te l'ai dis, je vais le relire, s'est une réponse de haut niveau et je dois le lire et le relire avant de bien comprendre.

    Encore un grand pour ton aide.

    beegees

  18. #18
    Membre éprouvé
    Avatar de beegees
    Homme Profil pro
    Développeur Web
    Inscrit en
    Mars 2004
    Messages
    3 610
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 49
    Localisation : Belgique

    Informations professionnelles :
    Activité : Développeur Web
    Secteur : Enseignement

    Informations forums :
    Inscription : Mars 2004
    Messages : 3 610
    Points : 1 277
    Points
    1 277
    Par défaut
    Citation Envoyé par raptor70 Voir le message
    Ce serait bien comme item dans la ce mini article
    Entierrement d'accord avec toi .

    beegees

  19. #19
    Rédacteur/Modérateur
    Avatar de JolyLoic
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2004
    Messages
    5 463
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 50
    Localisation : France, Yvelines (Île de France)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Août 2004
    Messages : 5 463
    Points : 16 213
    Points
    16 213
    Par défaut
    Citation Envoyé par coyotte507 Voir le message
    Et si le prototype avait été bool Ajouter(CRectangle Modele) ?

    Il y a deux cas possibles:
    [LIST=1][*]Si tu crées l'objet dans ton appel à la fonction, comme tu le fais:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    m_TC.Ajouter(CCercle(CC.Champs(1),atof(CC.Champs(2)));
    Alors l'objet est créé et passé tel quel à ta fonction, en effet il n'est pas utilisé en dehors alors pourquoi en faire une copie?
    Peut-être que ça ne sert à rien, mais rien n'empêche le compilateur d'en faire quand même la copie s'il le souhaite.

  20. #20
    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 beegees Voir le message
    <snip>
    Saurais-tu me dire ce que tu entends pas alias ?
    <snip>
    Exactement ce que l'on entend par la définition classique du terme alias:

    Il s'agit tout simplement de l'autre nom sous lequel est connu une chose ou une personne.

    Ici, cela signifie tout simplement que, quand tu passe un argument sous la forme d'une référence, la variable identifiée dans la fonction appelée est exactement celle qui a servi d'argument dans la fonction appelante.

    Au final, si tu apporte une modification quelconque dans la fonction appelée, cette modification persiste, après l'appel de la fonction, dans la fonction appelante.

    simplement, je voulais faire comprendre que, si tu as une fonction du genre de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    void fonction(UnType& monArg);
    et que tu l'appelle sous la forme de
    La variable qui s'appelait maVar dans la fonction appelante s'appelle monArg, dans la fonction.

Discussions similaires

  1. Réponses: 0
    Dernier message: 18/06/2012, 16h33
  2. Réponses: 0
    Dernier message: 23/04/2012, 13h55
  3. Réponses: 0
    Dernier message: 01/09/2010, 10h28
  4. Réponses: 2
    Dernier message: 22/02/2008, 10h54
  5. [VBA-E]Tester si une cellule est vide dans un cas particulier
    Par tonnick dans le forum Macros et VBA Excel
    Réponses: 3
    Dernier message: 26/09/2007, 10h12

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