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 :

Initialisation d'un objet en tant qu'attribut d'une classe


Sujet :

C++

  1. #1
    Membre à l'essai
    Profil pro
    Inscrit en
    Février 2010
    Messages
    21
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2010
    Messages : 21
    Points : 11
    Points
    11
    Par défaut Initialisation d'un objet en tant qu'attribut d'une classe
    Bonsoir à tous,

    Je bloque sur un exercice dans lequel une classe MaDate possède un attribut jour et mois de la classe MonEntier.
    Pour initiliaser jour et mois lors de l'appel du constructeur avec paramètres MaDate(int,int) (paramètres jour.n et mois.n) l'exercice stipule qu'il faut faire appel au constructeur paramétrique de MonEntier(int,int,int).
    J'ai tenté de faire appel au constructeur dans la définition de la classe MaDate(en tapant MonEntier jour(1,30,1)//) mais au lieu d'initialiser les attributs de la classe MaDate un nouvel objet est crée sans lien avec l'attibut jour, d'où ma question comment initialiser les attributs d'une classe lorsque ceux-ci sont des objets lors de l'appel du constructeur avec paramètres de la classe?

  2. #2
    Membre expert
    Avatar de Klaim
    Homme Profil pro
    Développeur de jeux vidéo
    Inscrit en
    Août 2004
    Messages
    1 717
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur de jeux vidéo
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Août 2004
    Messages : 1 717
    Points : 3 344
    Points
    3 344
    Par défaut
    Si j'ai bien compris ta description, tu as l'air d'avoir fait ce qu'il faut. Mais pour être sur, est-ce que tu peux nous montrer ton code ici et indiquer ce que tu es censé obtenir?

  3. #3
    Membre à l'essai
    Profil pro
    Inscrit en
    Février 2010
    Messages
    21
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2010
    Messages : 21
    Points : 11
    Points
    11
    Par défaut
    Bonjour Klaim, bonjour à tous

    Voilà le code des classes MonEntier et MaDate

    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
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
     #ifndef CLASSE_MONENTIER
    #define CLASSE_MONENTIER
    #include <cstdlib>
    #include <iostream>
    #include <math.h>
    using namespace std;
     
    //.h
    //classe MonEntier : borneInf<=n<=borneSup
    class MonEntier{
          private :
                  int borneInf;
                  int borneSup;
                  int n;
                  void setBornes(int,int);
                  //pramètres : borneInf,borneSup
     
          public :
     
                 //MonEntier();
                 MonEntier();
                 MonEntier(int,int,int);
                 //paramètres : borneInf,borneSup,n
                 int getBorneInf();
                 int getBorneSup();
                 void setN(int);//paramètre : n
                 int getN();
    };                 
    #endif
     
    //.cpp
    #include "MonEntier.h"
     
     
    MonEntier::MonEntier()
    {
           //initialiser la position par défaut d'un objet MonEntier
           cout << endl << "MonEntier constructeur par défaut" << endl ;
           borneInf = 0;
           borneSup = 100 ;
           n= 5;
    }
     
    MonEntier::MonEntier(int borneInf,int borneSup,int nombre)
    {
         //MonEntier avec paramètres
         cout << endl << "MonEntier constructeur avec paramètres" << endl ;
     
          setBornes(borneInf,borneSup);
          setN(nombre);
    }
     
    int MonEntier ::getBorneInf()
    {return this->borneInf;
    }       
     
    int MonEntier ::getBorneSup()
    {return this->borneSup;
    } 
     
    void MonEntier::setBornes(int borneInf,int borneSup)
     
    { if  (borneInf<=(borneSup))
          { this->borneInf=borneInf;
           this->borneSup=borneSup;
           }
      else cout <<"erreur :entrer une borne inférieure puis supérieure ";      
    }  
     
     
    void MonEntier:: setN(int n)
    {if (n<= this->borneSup && n>= this->borneInf)
        {this->n=n;
        }
     else
       {cout<<"erreur:n pas dans les bornes"<<endl;
       }  
    }   
     
    int MonEntier:: getN()
    {return this->n;
    }
     
    //.h
    #ifndef CLASSE_MADATE
    #define CLASSE_MADATE
    #include "MonEntier.h"
     
    using namespace std;
     
     
    class MaDate{
          private :
                  MonEntier jour; // compris entre 1 et 30
                  MonEntier mois;//compris entre 1 et 12
                  MonEntier annee;// compris entre 1 et 5000
          public :
                 MaDate();
                 MaDate(int,int,int); 
                 //paramètres jour,mois,année
                 void setJour(int);
                 void setMois(int);
                 void setAnnee(int);
                 int getJour();
                 int getMois();
                 int getAnnee();
                 void addJour(int);//nb.jours
                 void addMois(int);
                 void addAnnee(int);
     
    };
     
    // .cpp                          
    #include "MaDate.h"
    #include "MonEntier.h"
     
    MaDate::MaDate()
    {MonEntier jour(1,30,1);
     MonEntier mois(1,12,1);
     MonEntier annee(1,5000,1);
     
    }
     
    MaDate::MaDate(int v_jour,int v_mois,int v_annee)
    {MonEntier jour(1,30,v_jour);
     MonEntier mois(1,12,v_mois);
     MonEntier annee(1,5000,v_annee);
     // je souhaite initialiser les attributs de MaDate
    }
     
     
    #endif
    Lorsque je crée dans le main un objet MaDate ex(23,11,2009), les attributs jour,mois et année ne sont pas initiliasés comme je le souhaite mais c'est le constructeur par défaut de MonEntier qui est appelé.

    Merci d'avance pour vos éclaircissements

  4. #4
    jmv
    jmv est déconnecté
    Membre confirmé Avatar de jmv
    Profil pro
    Enseignant
    Inscrit en
    Mai 2004
    Messages
    395
    Détails du profil
    Informations personnelles :
    Localisation : France, Ille et Vilaine (Bretagne)

    Informations professionnelles :
    Activité : Enseignant

    Informations forums :
    Inscription : Mai 2004
    Messages : 395
    Points : 603
    Points
    603
    Par défaut
    Salut,
    Citation Envoyé par naspen Voir le message
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    MaDate::MaDate()
    {MonEntier jour(1,30,1);
     MonEntier mois(1,12,1);
     MonEntier annee(1,5000,1);
     
    }
    Dans ce constructeur tu crée 3 objets locaux qui seront détruits dès qu'on sort du constructeur. Il faut initialiser les 3 attributs.

    Soit comme ça :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    MaDate::MaDate()
    {
        jour.setBornes(1,30); // pb : setBornes() est privée
        jour.setN(1);
        // idem pour mois et annee 
    }
    Mais ça ne compilera pas car setBornes() est privée.

    Soit par une liste d'initialisation en utilisant un constructeur de MonEntier, regarde ton cours

  5. #5
    Membre expert
    Avatar de Klaim
    Homme Profil pro
    Développeur de jeux vidéo
    Inscrit en
    Août 2004
    Messages
    1 717
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur de jeux vidéo
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Août 2004
    Messages : 1 717
    Points : 3 344
    Points
    3 344
    Par défaut
    J'ajoute qu'un constructeur par copie et un opérateur de copie seraient les bienvenu dans ta classe MonEntier et te permettraient de faire :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     
    MaDate::MaDate()
    {
        jour = MonEntier(1,30,1);
        mois = MonEntier(1,12,1);
        annee = MonEntier(1,5000,1);
    }

  6. #6
    Inactif  


    Homme Profil pro
    Inscrit en
    Novembre 2008
    Messages
    5 288
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 48
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Secteur : Santé

    Informations forums :
    Inscription : Novembre 2008
    Messages : 5 288
    Points : 15 620
    Points
    15 620
    Par défaut
    En fait, il n'est pas nécessaire, dans ce cas, de redéfinir le constructeur par copie et l'opérateur de copie : ceux créés automatiquement par le compilateur fonctionnent sans problème ici (pas de pointeur dans la classe).

    Donc la solution de Kleim fonctionne avec la classe actuelle. Par contre, elle ne respecte pas l'énoncé de l'exercice :
    l'exercice stipule qu'il faut faire appel au constructeur paramétrique de MonEntier(int,int,int).
    Pour trouver la réponse, jmv a déjà donné la piste à suivre.

  7. #7
    Membre expert
    Avatar de Klaim
    Homme Profil pro
    Développeur de jeux vidéo
    Inscrit en
    Août 2004
    Messages
    1 717
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur de jeux vidéo
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Août 2004
    Messages : 1 717
    Points : 3 344
    Points
    3 344
    Par défaut
    L'operateur de copie par défaut ne passera pas par setN()...

  8. #8
    Membre à l'essai
    Profil pro
    Inscrit en
    Février 2010
    Messages
    21
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2010
    Messages : 21
    Points : 11
    Points
    11
    Par défaut
    Les listes d'initialisations ne nous ont pas été introduites mais après une petite recherche j'ai essayé ceci :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    MaDate::MaDate(int v_jour, int v_mois,int v_annee) : jour(1,30,v_jour), mois(1,12,v_mois), annee(1,5000,v_annee)
    {
     
    }
    Et ça a marché! Merci pour vos indications qui guident vers la solution pour nous la faire découvrir par nous-même, c'est plus gratifiant.
    (Si je me suis emballé et que ça a marché par chance ou/et que c'est syntaxiquement incorrect , prière de me dégonfler...)

  9. #9
    Inactif  


    Homme Profil pro
    Inscrit en
    Novembre 2008
    Messages
    5 288
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 48
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Secteur : Santé

    Informations forums :
    Inscription : Novembre 2008
    Messages : 5 288
    Points : 15 620
    Points
    15 620
    Par défaut
    Non, c'est bon

    L'operateur de copie par défaut ne passera pas par setN()...
    On est un peu hors sujet...

    On est d'accord que le operateur de copie par défaut fait une copie bits par bits, donc sans vérification des données. Ca peut être une raison de le définir.

    Ici, ça ne pose pas de problème : l'objet temporaire est créé en utilisant le constructeur paramétrique (qui fait lui même appelle à setN). On est donc sur que l'objet contient des données valides et on peut le copier sans problème avec l'operateur de copie.

  10. #10
    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
    Salut, et bienvenue sur le forum
    Citation Envoyé par naspen Voir le message
    Bonjour Klaim, bonjour à tous

    Voilà le code des classes MonEntier et MaDate

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     #ifndef CLASSE_MONENTIER
    #define CLASSE_MONENTIER
    #include <cstdlib>
    #include <iostream>
    #include <math.h>
    using namespace std;
    /*<snip>
    Attention, JAMAIS de directive using namespace dans un fichier d'en-tête...

    Ces sales bêtes ont la sale manie de se répandre partout du fait du jeu de l'inclusion en cascade, et tu perd toute l'utilité des espaces de noms
    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
     
    //classe MonEntier : borneInf<=n<=borneSup
    class MonEntier{
          private :
    //snip
     
          public :
     
    // snip
                 //paramètres : borneInf,borneSup,n
                 /* ATTENTION 1 */
                 int getBorneInf(); 
                 int getBorneSup();
                 /* ATTENTION 2 */
                 void setN(int);//paramètre : n 
                 int getN();
    };                 
    #endif
    ATTENTION 1:
    De manière générale, les accesseurs devraient être déclarés sous la forme de fonctions constantes...

    Parce que seules les fonctions constantes peuvent être appelées sur des objets constants, et que tu risques fort d'avoir des objets constants bien plus souvent que tu ne le crois

    ATTENTION 2
    De manière générale j'ai tendance à me méfier énormément des mutateurs (les setXXX):

    D'abord parce que, si c'est pour quand même définir un accesseur et un mutateur sur un membre et, par la même donner un acces aussi bien en lecture qu'en écriture, on en vient rapidement à se poser la question de savoir pourquoi diable défini le membre privé.

    Ensuite parce que tu objet est sensé être initialisé au moment de la création...

    Les changements de valeur que l'on observera sur un des membres seront donc le cas de modifications, dont il est souvent nécessaire de vérifier la vailidité avant de les accepter.

    Pour ton entier, tu peux l'additionner, le soustraire, le muptiplier ou le divisier à un autre, tu peux en demander le modulo par rapport à un autre, la racine carrée ou l'exposant nieme, mais, tu ne peux pas faire en sorte qu'un trois devienne un quatre... Ton trois ne vaudra jamais que... trois.

    S'il te faut un quatre, ou si tu veux obtenir le résultat de l'une de ces opération, tu obtiendra toujours... un nouvel objet.

    Enfin, quand ta classe n'a pas sémantique de valeur, le mutateur représente en réalité souvent une transition, c'est à dire l'étape de changement entre deux états, et il est largement préférable d'identifier les transitions de manière unique et non ambigüe.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
     
    MonEntier::MonEntier()
    {
           //initialiser la position par défaut d'un objet MonEntier
           cout << endl << "MonEntier constructeur par défaut" << endl ;
           borneInf = 0;
           borneSup = 100 ;
           n= 5;
    }
    Tel qu'il est écrit, ce constructeur par défaut ne devrait pas être...

    En effet, tu donne à ton constructeur une responsabilité qui ne devrait en aucun cas être sienne, à savoir... afficher(qui plus est, uniquement au travers de la console) quelque chose

    Il est vrai que cela peut te permettre de constater que tu es effectivement dans le constructeur par défaut, mais, en toute état de cause, cela ne devrait pas rester tel quel dans un code "de production"

    En plus, il est toujours préférable d'utiliser les listes d'initialisation.

    Dans l'exemple présent, cela n'a pas énormément d'importance, parce que les différents membres sont des types primitifs, mais, lorsque tu commencera à manipuler des objets dont les membres sont eux même de type non primitifs, tu te payera le cout d'une copie et d'une affectation là où le seul cout d'une copie suffirait... avec le plus souvent une sérieuse perte de performance à la clé
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    MonEntier::MonEntier(int borneInf,int borneSup,int nombre)
    {
         //MonEntier avec paramètres
         cout << endl << "MonEntier constructeur avec paramètres" << endl ;
     
          setBornes(borneInf,borneSup);
          setN(nombre);
    }
    J'ai déjà argumenté sur le fait que je n'aimais pas les mutateurs...

    Et il se fait qu'ici, tu n'en a pas besoin.

    En effet, il faut comprendre que l'appel d'une fonction a le plus souvent un cout, même si la fonction ne fait rien:

    Sauf cas particulier des fonctions inline, chaque appel d'une fonction va, en gros, être divisé en trois tâches:
    1. mise sur la pile d'appel d'une série d'informations concernant la fonction appelante
    2. exécution de la fonction appelée
    3. récupération de la pile d'appel des informations concerant la fonction appelante
    Tu pourrais très bien t'en passer, étant donné qu'il suffirait, au pire, d'affecter directement les différentes valeurs aux membres de ta classe.

    L'idéal étant, encore une fois, de recourir aux listes d'affectation (cf plus haut)
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
     
    void MonEntier::setBornes(int borneInf,int borneSup)
     
    { if  (borneInf<=(borneSup))
          { this->borneInf=borneInf;
           this->borneSup=borneSup;
           }
      else cout <<"erreur :entrer une borne inférieure puis supérieure ";      
    }
    je ne suis déjà pas partisan des mutateurs simples, tu comprendra que je sois encore moins partisan des mutateurs multiples

    De plus, l'utilisation de this dans une fonction membre n'est pas obligatoire car elle est implicite

    Je pourrais refaire toutes les remarques concernant ta classe date

    Par contre, elle met en évidence un problème supplémentaire: tu as, visiblement, très mal évalué les différentes responsabilité des différents objets...

    En effet, il y a peu de raisons de créer un objet "mon entier" pour représenter une date, par contre, la classe date devrait d'elle-même savoir quelles sont les limites admises pour ses différents membres...

    L'idéal serait de définir ces limites sous la forme de membres statiques constants ou de fonctions statiques, de manière à ce qu'elles soient partagée par... l'ensemble des objets de type date que tu pourrait créer.

    Les membres statiques constants que tu créerais seraient:
    1. static const int minAnnee = 1
    2. static const int maxAnnee = 5000
    3. static const int minJour = 1
    4. static const int minMois = 1
    5. static const int maxMois = 12

    et tu aurais une fonction statique (ou une fonction libre "amie") qui, sur base des donnée contenue dans chaque date fournirait... le nombre de jours maximum adapté au mois indiqué :
    • 31 pour janvier, mars, mai, juillet, aout, octobre et décembre,
    • 30 pour avril, juin, septembre et novembre,
    • 28 ou 29 (selon la "bissextilité" ) de l'année pour février)

    Selon l'usage que tu peux avoir de ces informations, ces membres et cette fonction peuvent être au choix puliques (ce sont des constantes, donc cela ne présente aucun danger) ou privées, mais sans fournir ni accesseur (autrement autant les garder publiques), ni, encore moins, de mutateur (qui n'aurait aucun sens sur des valeurs constantes)
    Citation Envoyé par Klaim Voir le message
    J'ajoute qu'un constructeur par copie et un opérateur de copie seraient les bienvenu dans ta classe MonEntier et te permettraient de faire :
    Heuu, tu veux sans doute parler d'un opérateur d'affectation, non
    Citation Envoyé par gbdivers Voir le message
    On est d'accord que le operateur de copie par défaut fait une copie bits par bits, donc sans vérification des données. Ca peut être une raison de le définir.
    Non, malheureux...

    Un constructeur fait une copie membre à membre de l'objet, en invoquant l'opérateur par copie de chacun des membres de l'objet passé en paramètre.

    Les problèmes surviennent lorsque l'un des membres est un pointeur:

    En effet, un pointeur n'est jamais... qu'une valeur numérique entière (non signée) représentant... l'adresse à laquelle se trouve la variable pointée.

    C'est donc l'adresse et non... la variable qui est copiée, avec comme résultat le fait que deux objets distincts peuvent parfaitement partager une même variable.

    Le résultat est donc des plus dangereux car on se retrouve facilement soit face à une situation dans laquelle on tente de libérer deux fois de la mémoire, soit dans laquelle on risque d'essayer d'accéder à une adresse devenue invalide du fait de sa libération "par l'autre objet qui vient d'être détruit"...
    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
    Inactif  


    Homme Profil pro
    Inscrit en
    Novembre 2008
    Messages
    5 288
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 48
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Secteur : Santé

    Informations forums :
    Inscription : Novembre 2008
    Messages : 5 288
    Points : 15 620
    Points
    15 620
    Par défaut
    Tu m'apprends quelque chose koala1
    Je pensais que l'opérateur de recopie par défaut faisait de la copie bit par bit (j'ai testé pour être sur habituellement, ca ne me pose pas de problème) Ca change pas grand chose à ce que je disais puisse que j'avais bien précisé que l'opérateur par défaut fonctionnait dans ce cas puisse qu'on n'avais pas de pointeur dans la classe.

    Mais du coup, ça peut changer beaucoup de chose, en cas de classes héritant de nombreux parents : on risque d'avoir plusieurs centaines d'appel de fonction de recopie lors d'une copie d'objet.

    EDIT : je me souviens d'où j'ai pondu cette idée de copie bit par bit : lorsque l'on écrit une fonction clone pour un pattern, on utilise souvent (en tout cas dans le tutoriel du site sur les pattern) une copie plutôt qu'un new :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    A* A::Clone() const 
    {
       return (new A(*this));
    }
    au lieu de :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    A* A::Clone() const 
    {
       return (new A());
    }
    justement parce qu'il me semblait que c'était plus rapide de copier que de créer...
    Bref, si on veut juste obtenir une instance d'un objet polymorphe, pas besoin de recopie, ça ira aussi bien avec une création.
    Ou j'ai loupé quelque chose ?

  12. #12
    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
    Tout dépend de ce que tu veux faire en clonant ton objet...

    Si, en le clonant, tu veux "simplement" obtenir un objet avec des valeurs initialisées par défaut, tu peux, effectivement, te contenter d'appeler le constructeur... par défaut...

    Si, par contre, tu veux réellement cloner (comprend: avoir une copie fidèle de l'objet d'origine), tu devra invoquer... le constructeur par copie...

    Généralement, la sémantique donnée à clone est plus proche de cette deuxième possibilité
    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

  13. #13
    Inactif  


    Homme Profil pro
    Inscrit en
    Novembre 2008
    Messages
    5 288
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 48
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Secteur : Santé

    Informations forums :
    Inscription : Novembre 2008
    Messages : 5 288
    Points : 15 620
    Points
    15 620
    Par défaut
    J'allais répondre qu'en général (tout au moins ce que j'ai déjà rencontré ), on ajoute un objet dans une factory en utilisant le constructeur par défaut :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    myFactory->register("mon object", new myObject());
    et dans ce cas, autant utiliser une fonction clone sans copie...

    Mais il est vrai qu'on pourrait également utiliser la factory (et on sait jamais comment un utilisateur va utiliser notre factory) en enregistrant un même objet avec des paramètres différents :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    myFactory->register("mon objet 1", new myObject(1));
    myFactory->register("mon objet 2", new myObject(2));
    et dans ce cas, il faut absolument une fonction clone... qui clone !

    De toute façon, d'un point de vue sémantique, ça me choquerait d'appeler une fonction "clone"... qui ne clone pas.

    Bref, j'arrête de polluer ce post avec mes questions existentielle sur le clonage
    Merci koala01

  14. #14
    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
    Citation Envoyé par gbdivers Voir le message
    J'allais répondre qu'en général (tout au moins ce que j'ai déjà rencontré ), on ajoute un objet dans une factory en utilisant le constructeur par défaut :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    myFactory->register("mon object", new myObject());
    et dans ce cas, autant utiliser une fonction clone sans copie...

    Mais il est vrai qu'on pourrait également utiliser la factory (et on sait jamais comment un utilisateur va utiliser notre factory) en enregistrant un même objet avec des paramètres différents :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    myFactory->register("mon objet 1", new myObject(1));
    myFactory->register("mon objet 2", new myObject(2));
    et dans ce cas, il faut absolument une fonction clone... qui clone !

    De toute façon, d'un point de vue sémantique, ça me choquerait d'appeler une fonction "clone"... qui ne clone pas.

    Bref, j'arrête de polluer ce post avec mes questions existentielle sur le clonage
    Merci koala01
    A vrai dire, la fonction clone sera essentiellement utilisée lorsque l'on veut rendre obligatoire le passage par un système donné (la factory ) pour la création d'un objet, généralement dans le but de maitriser d'avantage la durée de vie de l'objet créé ou dans celui de casser les dépendances trop rigides.

    Elle sera souvent utilisée en conjonction avec une amitié et le fait de déclarer les constructeurs en accessibilité privée, de telle sorte que seule la factory (ou système équivalent) soit en mesure de créer les objets.

    Il y a donc pas mal de chances pour qu'un code proche de ceux que tu présente soit purement et simplement refusé parce que... le constructeur (qu'il soit par défaut ou non) serait privé

    Généralement, tu auras donc, dans le cadre de la factory, une fonction membre (init ) qui profitera de l'amitié avec les différentes classes pour... en créer un exemplaire et l'enregistrer comme élément clonable.

    Mais la factory peut fonctionner, selon le contexte, de deux manières bien distinctes:

    Soit en maintenant dans sa collection des objets pleinement définis (qui ne nécessitent aucune modification avant d'être renvoyé à la fonction demandeuse), et la fonction giveMeSomething qui renvoie la nouvelle instance ne prend pas d'argument et se contente d'appeler clone()

    Soit en maintenant dans sa collection des objets "partiellement définis" (qui nécessitent certaines modifications entre leur clonage et leur renvoi), et la fonction giveMeSomething utilise un ou plusieurs argument(s) passé(s) pour terminer l'initialisation de l'objet avant de renvoyer l'instance nouvellement créée.

    Selon le cas, tu peux préférer un contexte ou l'autre, mais la décision doit être prise en fonction du projet sur lequel tu travaille
    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

  15. #15
    Membre à l'essai
    Profil pro
    Inscrit en
    Février 2010
    Messages
    21
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2010
    Messages : 21
    Points : 11
    Points
    11
    Par défaut
    J'ai lu avec beaucoup d'attention les remarques de koala1 (et des autres) : je souhaite tout de même préciser que l'énoncé de l'exercice est donné tel quel (les méthodes et la définition des objets nous étaient imposées).
    Je pense que l'exercice a une visée plus pédagogique qu'orientée vers une production <<efficace>> de code, débutant oblige.

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

Discussions similaires

  1. [PHP 5.0] Objet en tant qu'attribut dans une classe
    Par yassinozi dans le forum Langage
    Réponses: 6
    Dernier message: 03/02/2014, 09h23
  2. Passer un objet comme attribut d'une classe
    Par Leduc08 dans le forum Ext JS / Sencha
    Réponses: 1
    Dernier message: 05/04/2011, 11h54
  3. Réponses: 2
    Dernier message: 27/03/2005, 16h09
  4. [VB.NET] Parcourir les attributs d'une classe
    Par pasqwal dans le forum Windows Forms
    Réponses: 3
    Dernier message: 15/02/2005, 09h47
  5. Réponses: 7
    Dernier message: 08/01/2005, 13h24

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