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 :

constructeur de recopie


Sujet :

C++

  1. #1
    Membre du Club
    Inscrit en
    Février 2011
    Messages
    188
    Détails du profil
    Informations forums :
    Inscription : Février 2011
    Messages : 188
    Points : 51
    Points
    51
    Par défaut constructeur de recopie
    Salut,

    J'ai une classe C11 hérité de la classe mère C1.

    Dans ma fonction main je fais appel au constructeur de recopie de la classe C11. Mais le problème que la classe C11 possède un constructeur paramétré et pas un constructeur de recopie. Est il logique?
    remarque : C11 possède des attributs de type pointeur.

    Merci d'avance.

  2. #2
    Inactif  


    Homme Profil pro
    Doctorant sécurité informatique — Diplômé master Droit/Économie/Gestion
    Inscrit en
    Décembre 2011
    Messages
    9 012
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 31
    Localisation : France, Loire (Rhône Alpes)

    Informations professionnelles :
    Activité : Doctorant sécurité informatique — Diplômé master Droit/Économie/Gestion
    Secteur : Enseignement

    Informations forums :
    Inscription : Décembre 2011
    Messages : 9 012
    Points : 23 145
    Points
    23 145
    Par défaut
    Bonjour,

    Je présume que tu parles du constructeur par copie :
    Est il logique?
    Cela dépend de la sémantique de ta classe.

    Sémantique d'entité :
    • Les instances sont toutes "uniques" et "différentes", ex : Homme("Pierre") != Homme("Pierre")
    • Pas de constructeur par copie ni d'opérateur de copie mais éventuellement une méthode clone() ;
    • La comparaison "inférieur"/"supérieur" n'a pas de sens, ont doit comparer les instances "par rapport à".


    Sémantique de valeur :
    • Les instances sont "identiques" si elles ont certains champs en communs. ex : NombreComplexe(5,5) == NombreComplexe(5,5);
    • La copie a un sens mais l'héritage n'a alors pas de sens
    • La comparaison "inférieur"/"supérieur" a un sens.


    Mais bon, dès que koala01 verra ce post, il va te pondre un gros pavé pour tout bien t'expliquer
    Au pire, tu peux aller faire une recherche avancée sur le forum pour trouver les messages où il parle de sémantique d'entité/valeur.

  3. #3
    Membre émérite
    Avatar de imperio
    Homme Profil pro
    Étudiant
    Inscrit en
    Mai 2010
    Messages
    852
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Ain (Rhône Alpes)

    Informations professionnelles :
    Activité : Étudiant
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Mai 2010
    Messages : 852
    Points : 2 298
    Points
    2 298
    Par défaut
    La FAQ peut aussi t'aider.

    Mais bon, dès que koala01 verra ce post, il va te pondre un gros pavé pour tout bien t'expliquer
    Tu lui fais une reputation terrible !

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

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 614
    Points : 30 626
    Points
    30 626
    Par défaut
    Salut,
    Citation Envoyé par kochfet Voir le message
    Salut,

    J'ai une classe C11 hérité de la classe mère C1.

    Dans ma fonction main je fais appel au constructeur de recopie de la classe C11. Mais le problème que la classe C11 possède un constructeur paramétré et pas un constructeur de recopie. Est il logique?
    C'est en effet "logique", dans le sens où, si tu ne définis pas le constructeur de copie, C++ va en fournir un d'office afin de respecter la forme canonique orthodoxe de Coplien.

    L'implémentation "naïve" de ce constructeur qui sera implémenté par C++ consiste à copier le contenu "membre à membre", dans l'ordre de leur déclaration.

    Autrement dit, si tu as une classe "point" qui prend la forme de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    class Point{
        public:
        Point() : x_(0),y_(0){}
        Point(int x, int y):x_(x),y_(y){}
        int x() const{return x_;}
        int y() const{return y_;}
    private:
        int x_;
        int y_;
    }:
    le compilateur fournira d'office un constructeur de copie ressemblant à Point(Point const& other) dont l'implémentation copiera other.x_ dans x_ et other.y_ dans y_. La norme garanti même que cela se fera dans cet ordre bien précis, et non y_ en premier
    remarque : C11 possède des attributs de type pointeur.
    Ca, ca peut potentiellement poser problème, car, si ce sont des pointeurs nus (comprends : que tu n'utilises pas les pointeurs intelligents comme std::shared_ptr ou std::unique_ptr) c'est uniquement l'adresse de l'élément qui sera copiée.

    Un pointeur n'est en effet rien d'autre qu'une valeur numérique entière (généralement non signée) qui correspond à l'adresse mémoire à laquelle on pourra trouver l'élément du type indiqué qui nous intéresse. Si tu ne définis pas correctement le constructeur de copie, ce n'est que cette adresse qui sera copiée, alors que ce que tu veux c'est souvent que l'objet pointé soit lui-même copié. On parle de "copie en profondeur".

    C'est la raison pour laquelle tu dois définir le constructeur de copie pour ta classe C11. Mais, n'oublies pas la règle des trois grands qui dit que, si tu dois définir une des fonctions que sont le constructeur de copie, l'opérateur d'affectation ou le destructeur, alors, tu devra définir les deux autres aussi

    Ceci étant dit, je tiens quand même à attirer ton attention sur un problème tout particulier : la sémantique de tes classes.

    Toutes les classes que l'on peut créer peuvent en effet être classées dans deux catégories distinctes: les classes ayant sémantique de valeur et les classe ayant sémantique d'entité.

    Une classe ayant sémantique de valeur est, typiquement, une classe dont il peut exister, à un instant T, plusieurs instances présentant exactement les mêmes valeurs en mémoire. C'est le cas de la classe Point que je t'ai présentée plus haut, d'une éventuelle classe couleur, de la classe std::string, fournie par le langage, pour ne donner que quelques exemples.

    Ces classes sont typiquement:
    • copiables et affectables (la forme canonique orthodoxe de coplien est de stricte application)
    • comparables au minimum par égalité : il y a du sens à demander si la couleur couleur1 est égale à la couleur couleur2
    • peu enclines à intervenir dans une hiérarchie de classe : il n'est pas possible de les utiliser dans un héritage privé, que ce soit comme classe de base ou comme classe dérivée.

    Quant aux classes ayant sémantique d'entité, ce sont des classes dont il ne peut typiquement pas exister plusieurs instances présentant exactement les mêmes valeurs à un instant T pour éviter d'essayer d'appliquer à l'une les modifications qui devraient être appliquées à l'autre.

    C'est, typiquement le cas de classes comme CompteBanquaire, Personne, voiture, Maison, Chat et autres, Bref, toutes les classes qui doivent garantir une "unicité référentielle". Parce que tu serais très faché si ton salaire arrivait sur le compte bancaire de ton voisin, ou si la traite de sa mazerati était déduite du tien

    Typiquement, ces classes:
    • ne sont ni copiables, ni affectables, pour assurer l'unicité référentielle
    • ne sont pas comparables "globalement" par égalité, bien qu'il soit tout à fait possible de comparer certaines valeurs qu'elles exposent (le numéro du compte ou son solde).
    • sont identifiables de manière unique et non ambiguë: il y a toujours une (ou plusieurs) informations qui te permettent de t'assurer que l'on parle bien de toi et non d'un autre kochfet qui existerait "par ailleurs"
    • sont particulièrement adaptée à l'héritage multiple : voiture pourrait hériter de Véhicule, Maison pourrait hériter de Batiment, CompteBancaire pourrait être dérivé en CompteCourant et CompteEpargne.
    Si tu veux que C11 hérite de C1, tes deux classes ont, d'office, sémantique d'entité. Il n'y a donc aucun sens à essayer de définir le constructeur de copie, ni l'opérateur d'affectation car ces deux classes ne devraient pas être copiables ni affectables.

    Ce qu'il faudrait faire, c'est surtout faire en sorte ce C1 ne soit ni copiable ni affectable. Cela suffira pour t'assurer que toutes les classes dérivées de C1 ne le soient pas non plus .

    Si tu peux utiliser les fonctionnalités de C++11, le plus facile est de déclarer les constructeurs de copie et opérateur d'affectation comme étant delete, sous la forme de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    class C1{
    public:
        C1(C1 const &) = delete;
        C1 & operator=(C1 const &) = delete;
        /* ... */
    };
    Si tu n'as pas accès aux possibilités de C++11, tu peux faire hériter de manière privée ta classe C1 de boost::noncopyable sous une forme proche de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    #include <boost/utility.hpp>
    class C1 : private boost::noncopyable{
        /* ... */
    };
    Si tu ne disposes d'aucune de ces possibilités, tu peux utiliser la méthode "à l'ancienne" en désespoir de cause : déclarer sans les définir le constructeur de copie et l'opérateur d'affectation de ta classe C1 dans l'accessibilité privée
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    class C1{
        /* ... */
    private:
        C1(C1 const &); // !!! on n'en donne pas d'implémentation !!!
        C1 & operator=(C1 const &);// !!! on n'en donne pas d'implémentation !!!
    };
    De cette manière, si tu essayes de faire une copie ou une affectation des classes dérivées, le compilateur se plaindra que "C1(C1 const &) est privé dans ce contexte" et, si tu essayes de faire une copie de C1, la compilation passera, mais c'est l'éditeur de liens qui se plaindra de ne pas trouver le symbole correspondant au constructeur de copie (ou à l'opérateur d'affectation).

    Bref, dans tous les cas, tu seras "bloqué" avant l'exécution et tu éviteras donc de te retrouver avec deux instances totalement identiques d'un objet identifié de manière unique et non ambiguë, car cela serait source d'énormément de problèmes

    Citation Envoyé par imperio Voir le message
    La FAQ peut aussi t'aider.



    Tu lui fais une reputation terrible !
    Ouaip, mais bon, il me connaît C'est pas pour rien que je me suis retrouvé bombardé "auteur édité", car une conception juste mon principal cheval de bataille sur ce forum

    En plus, il n'avait pas tord, hein?
    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
    Inactif  


    Homme Profil pro
    Doctorant sécurité informatique — Diplômé master Droit/Économie/Gestion
    Inscrit en
    Décembre 2011
    Messages
    9 012
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 31
    Localisation : France, Loire (Rhône Alpes)

    Informations professionnelles :
    Activité : Doctorant sécurité informatique — Diplômé master Droit/Économie/Gestion
    Secteur : Enseignement

    Informations forums :
    Inscription : Décembre 2011
    Messages : 9 012
    Points : 23 145
    Points
    23 145
    Par défaut
    Citation Envoyé par koala01 Voir le message
    };[/CODE]Si tu ne disposes d'aucune de ces possibilités, tu peux utiliser la méthode "à l'ancienne" en désespoir de cause : déclarer sans les définir le constructeur de copie et l'opérateur d'affectation de ta classe C1 dans l'accessibilité privée
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    class C1{
        /* ... */
    private:
        C1(C1 const &); // !!! on n'en donne pas d'implémentation !!!
        C1 & operator=(C1 const &);// !!! on n'en donne pas d'implémentation !!!
    };
    EN C++11 (loué soit-il), tu peux aussi faire :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    class C1{
        /* ... */
    private:
        C1(C1 const &) = delete;
        C1 & operator=(C1 const &) = delete;
    };
    A noter aussi qu'en C++11, tu peux faire :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    class A final
    {
            //...
    };
    Pour interdire les autres classes d'hériter de "A".

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

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 614
    Points : 30 626
    Points
    30 626
    Par défaut
    Citation Envoyé par Neckara Voir le message
    EN C++11 (loué soit-il), tu peux aussi faire :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    class C1{
        /* ... */
    private:
        C1(C1 const &) = delete;
        C1 & operator=(C1 const &) = delete;
    };
    Heu, je ne veux rien dire, mais ca, c'ést la toute première possibilité que j'ai envisagée . Si si, lis bien ma réponse, je t'assures

    Bon, d'accord, toi, tu les as fait passer en privé alors que je les laissais en public. Mais il n'y a aucune obligation à les faire passer en privé
    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
    Inactif  


    Homme Profil pro
    Doctorant sécurité informatique — Diplômé master Droit/Économie/Gestion
    Inscrit en
    Décembre 2011
    Messages
    9 012
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 31
    Localisation : France, Loire (Rhône Alpes)

    Informations professionnelles :
    Activité : Doctorant sécurité informatique — Diplômé master Droit/Économie/Gestion
    Secteur : Enseignement

    Informations forums :
    Inscription : Décembre 2011
    Messages : 9 012
    Points : 23 145
    Points
    23 145
    Par défaut
    A en effet, j'ai dû louper un chapitre de ta réponse désolé.

  8. #8
    Membre expert
    Profil pro
    Inscrit en
    Mars 2007
    Messages
    1 415
    Détails du profil
    Informations personnelles :
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Mars 2007
    Messages : 1 415
    Points : 3 156
    Points
    3 156
    Par défaut
    Citation Envoyé par Neckara Voir le message
    Mais bon, dès que koala01 verra ce post, il va te pondre un gros pavé pour tout bien t'expliquer .
    Je me suis dit exactement la même chose et du coup j'ai eu la flemme de répondre .
    Find me on github

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

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 614
    Points : 30 626
    Points
    30 626
    Par défaut
    Citation Envoyé par Neckara Voir le message
    A en effet, j'ai dû louper un chapitre de ta réponse désolé.
    Bah, tu es tout excusé

    Citation Envoyé par jblecanard Voir le message
    Je me suis dit exactement la même chose et du coup j'ai eu la flemme de répondre .
    Et tu n'es surement pas le seul dans le cas

    Décidément, je commence à être trop connu et prévisible sur ce forum
    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

  10. #10
    Membre émérite
    Profil pro
    Inscrit en
    Novembre 2004
    Messages
    2 764
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2004
    Messages : 2 764
    Points : 2 705
    Points
    2 705
    Par défaut
    Citation Envoyé par Neckara Voir le message
    A en effet, j'ai dû louper un chapitre de ta réponse désolé.
    Dis plutôt que tu as eu la flemme de tout lire.

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

Discussions similaires

  1. constructeur de recopie et héritage
    Par r0d dans le forum C++
    Réponses: 11
    Dernier message: 08/02/2006, 09h47
  2. QObject et constructeur de recopie
    Par ionnn dans le forum Qt
    Réponses: 12
    Dernier message: 07/01/2006, 11h50
  3. Constructeur par recopie
    Par KernelControl dans le forum C++
    Réponses: 2
    Dernier message: 29/12/2005, 12h24
  4. constructeur de recopie:question theorique
    Par voyageur dans le forum C++
    Réponses: 7
    Dernier message: 02/12/2004, 22h46
  5. Constructeur par recopie
    Par sdebrois dans le forum Composants VCL
    Réponses: 13
    Dernier message: 21/10/2004, 14h47

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