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 :

Constructeurs explicites


Sujet :

C++

  1. #1
    Débutant  
    Inscrit en
    Novembre 2006
    Messages
    1 073
    Détails du profil
    Informations forums :
    Inscription : Novembre 2006
    Messages : 1 073
    Points : 217
    Points
    217
    Par défaut Constructeurs explicites
    Autre question sur l'appel de fonction.
    Il semble qu'il y a des fonctions qui prennent des arguments, mais qui ne sont pas écrits, explicitement dans la liste d'arguments.
    Par exemple, la fonction f2 définie ici:

    http://msdn.microsoft.com/en-us/libr...48(VS.80).aspx

    je la redonne ici:
    C2 est une classe, mais il n'y a pas d'arguments. Que fait une telle fonction?
    Si on veut faire qqch de l'argument de type C2, que fait-on?
    merci

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

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 612
    Points : 30 612
    Points
    30 612
    Par défaut
    Dans le cas que tu présente, il est plus que possible que la fonction doive respecter une certaine signature, mais que, exceptionnellement (sans doute parce que c'est une fonction virtuelle), l'argument ne sera pas utilisé.

    Si nous nommions l'argument, le compilateur se plaindrait d'avoir une variable (non de l'argument) définie mais jamais utilisée.

    Si on souhaite pouvoir accéder à l'argument, il faudra lui donner un nom
    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

  3. #3
    Débutant  
    Inscrit en
    Novembre 2006
    Messages
    1 073
    Détails du profil
    Informations forums :
    Inscription : Novembre 2006
    Messages : 1 073
    Points : 217
    Points
    217
    Par défaut
    D'ailleurs, dans le code de la page MSDN, il y a une conversion, que je reproduis ici:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    void g(int i)
    {
        f2(i);   // C2558
        // try the following line instead
        // f2(C2(i));
    }
    Ne faudrait-il pas, pour être en conformité avec le C++, écrire:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
     f2(static_cast<C2>(i));
    plutôt que
    Enfin, quand on déclare un constructeur "explicit", et que l'on fait passer un argument par valeur, il y a appel du constructeur par copie.
    Mais je ne comprends pas pourquoi cela provoque une erreur.

    Car si on déclare un objet c (en l'occurence de classe C dans le cas présent)
    et que l'on fait par exemple:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
     
    C  f(C c){   
        c.i = 2;
        return c;   // first call to copy constructor
    }
    int main(){
     
        C c, d;
    d = f(c);    //   c is copied 
    }

    il y aura deux erreurs, l'une pour f(c) l'autre pour return c.
    mais où sera la conversion implicite?
    Merci

  4. #4
    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
    Cela correspond au 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
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    #include <iostream>
    class C
    {
    public:
        int i;
        explicit C(const C&)   // an explicit copy constructor
        {
            std::cout<<"\nin the copy constructor";
        }
        explicit C(int i )   // an explicit constructor
        {
            std::cout<<"\nin the constructor";
        }
     
        C()
        {
            i = 0;
        }
    };
     
    class C2
    {
    public:
        int i;
        explicit C2(int i )   // an explicit constructor
        {
        }
    };
     
    C f(C c)
    {   // C2558
        c.i = 2;
        return c;   // first call to copy constructor
    }
     
    void f2(C2)
    {
    }
     
    void g(int i)
    {
        f2(i);   // C2558
        // try the following line instead
        // f2(C2(i));
    }
     
    int main()
    {
        C c, d;
        d = f(c);   // c is copied
     
        return 0;
    }
    L'idée est de mettre en évidence partout où un constructeur était appelé. En le mettant explicit, cela force à appeler explicitement le constructeur et donc prendre conscience où ces appels avaient lieu.

  5. #5
    Débutant  
    Inscrit en
    Novembre 2006
    Messages
    1 073
    Détails du profil
    Informations forums :
    Inscription : Novembre 2006
    Messages : 1 073
    Points : 217
    Points
    217
    Par défaut
    oK, je sais bien. Mais en quoi ce code pose t il un pb au compilateur:
    quand je rentre ce code dans vC2010, j'ai pour erreur;
    class "C" has no suitable copy constructor


    De plus, ai-je raisons quant à ma remarque sur le static_cast?

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

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 612
    Points : 30 612
    Points
    30 612
    Par défaut
    Il faudrait voir de quoi est composé C, comment tu essaye de construire un objet de type C, et comment tu essaie de construire tes objets dont le type dérive de C.

    si tu essaye d'invoquer un constructeur de C prenant un paramètre alors qu'il n'existe aucune constructeur acceptant le type de paramètre en question, ou, au contraire, si tu essaye de construire C en ne lui fournissant aucun argument alors qu'il en attend un, fatalement, le compilateur ne pourra jamais déterminer quel constructeur il doit invoquer.

    C'est, en gros, ce que te dis le message d'erreur.

    Ainsi, il est plus que probable que tu aies une classe C proche de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    class C
    {
        public:
            explicite C(int i);
    };
    et que le constructeur de la classe C2 qui dérive de C n'appelle pas explicitement le constructeur... prenant un entier de C.

    Ou, c'est l'inverse qui se passe: C dispose d'un constructeur "par défaut", mais d'aucun constructeur demandant un entier, et tu essaye d'invoquer un constructeur pour C en lui donnant un entier.

    Et, pour répondre à ta dernière question, tu as tord au niveau du static_cast.

    Il faut comprendre que les static_/dynamic_/reinterpret_ cast provoquent ce que l'on appelle le transtypage.

    Cela revient à faire passer un(e référence ou un pointeur sur un) objet de type X pour un(e référence ou un pointeur sur un) objet Y, en appliquant des "normes de sécurité" variable au moment où on prend la décision.

    Cela implique que tu... dois avoir, effectivement, un objet à transtyper

    Le constructeur, quant à lui, permet de créer un objet "tout beau, tout propre" du type indiqué et d'en définir les membres sur base des informations que l'on transmet (et que l'on a sans doute récupérées par ailleurs).

    Par contre, une fois qu'un objet a été créé (que son constructeur a été appelé), on peut envisager de le transtyper en un autre, pour autant que l'on respecte certaines règles

    Il faut aussi noter que le transtypage n'a rien à voir avec une quelconque conversion...

    La création ou la conversion de type créent réellement une nouvelle variable, alors que le transtypage revient (en y allant, il est vrai, un peu fort) à mentir au compilateur sur le type de l'objet que l'on utilise
    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 du Club
    Profil pro
    Inscrit en
    Octobre 2005
    Messages
    57
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2005
    Messages : 57
    Points : 53
    Points
    53
    Par défaut
    Citation Envoyé par 3DArchi Voir le message
    Cela correspond au code :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
     
    C f(C c)
    {   // C2558
        c.i = 2;
        return c;   // first call to copy constructor
    }
    ....
     
    d = f(c);   // c is copied
    Attendez. Le 1er commentaire a l'air de dire que c'est a l'instruction return c que le constructeur de copie est appele. Si je ne m'abuse, c'est plutot au passage de parametre (et uniquement la) lors de l'appel suivant non ?

  8. #8
    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,
    La réponse est : les 2 !
    Une construction par copie a lieu lorsque le paramètre est transmis à la fonction. Mais le résultat aussi est retourné par valeur et provoque donc un appel au constructeur par copie.

  9. #9
    Modérateur
    Avatar de bruno_pages
    Homme Profil pro
    ingénieur informaticien à la retraite
    Inscrit en
    Juin 2005
    Messages
    3 533
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 64
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : ingénieur informaticien à la retraite
    Secteur : High Tech - Produits et services télécom et Internet

    Informations forums :
    Inscription : Juin 2005
    Messages : 3 533
    Points : 6 709
    Points
    6 709
    Par défaut
    c'est pour cela qu'il faut tant que faire ce peut ne pas passer les instances par valeur mais par référence constante, sinon le code passe son temps a recopier les éléments

    de même un getter sur un attribut retournera une référence constante et non la valeur recopiée
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
     
    class A {...};
     
    class B {
    public:
      void recopie_param(A a) {...}
      void pas_recopie_param(const A & a) { ... }
     
      A recopie_valeur() const { return a; }
      const A & pas_recopie_valeur() const { return a; }
     
    private:
      A a;
    };
    dans le cas ou la 'valeur' calculée par une opération est une collection ou autre structure complexe, il est préférable de ne pas rendre la valeur mais d'utiliser un paramètre de sortie, exemple :
    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
     
    #include <list>
    using namespace std;
     
    class A {
    public:
       list<A> duplicate1(unsigned n) {
          list<A> l;
     
          while (n--) l.push_back(this);
          return l;
       }
     
       void duplicate2(list<A> & l, unsigned n) {
         l.clear(); // to be sure
         while (n--) l.push_back(this);
       }
    };
    l'utilisation de duplicate1 provoque une recopie inutile de la liste temporaire et des A qu'elle contient
    Bruno Pagès, auteur de Bouml (freeware), mes tutoriels sur DVP (vieux, non à jour )

    N'oubliez pas de consulter les FAQ UML et les cours et tutoriels UML

  10. #10
    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 860
    Points
    11 860
    Par défaut
    Citation Envoyé par bruno_pages Voir le message
    c'est pour cela qu'il faut tant que faire ce peut ne pas passer les instances par valeur mais par référence constante, sinon le code passe son temps a recopier les éléments
    Je ne serais pas aussi catégorique que toi.

  11. #11
    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,
    Le code proposé par deublete est là pour illustrer les constructeurs explicites et y compris celui de copie.

Discussions similaires

  1. [POO] Constructeur devant être rendu explicite
    Par coyotte507 dans le forum C++
    Réponses: 2
    Dernier message: 12/11/2008, 23h12
  2. Constructeur explicite et tableau
    Par methodman225 dans le forum Collection et Stream
    Réponses: 5
    Dernier message: 04/09/2008, 12h59
  3. appel explicite au constructeur
    Par exhortae dans le forum C++
    Réponses: 17
    Dernier message: 01/03/2008, 16h05
  4. Appel explicite du constructeur de recopie ?
    Par sebkramm dans le forum C++
    Réponses: 6
    Dernier message: 21/11/2007, 10h02

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