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

Langage C++ Discussion :

Initialisation d'un objet contenu dans un autre.


Sujet :

Langage C++

  1. #1
    Membre à l'essai
    Profil pro
    Inscrit en
    Juin 2004
    Messages
    37
    Détails du profil
    Informations personnelles :
    Âge : 40
    Localisation : France

    Informations forums :
    Inscription : Juin 2004
    Messages : 37
    Points : 19
    Points
    19
    Par défaut Initialisation d'un objet contenu dans un autre.
    Bonjour !

    Je suis de nouveau confronté à un problème "basique" me sembe-t-il... Sans trouver d'indice dans la FAQ (probablement mal cherché)...

    J'ai un objet d'une classe "Contenant" qui a pour donnée membre un objet d'une classe "Contenu". "Contenu" a un constructeur sans paramètres et un constructeur prenant un string en argument.
    Je peux initialiser facilement Contenu par la liste d'initialisation du constructeur de contenant en lui passant un string.

    Mais un problème se pose lorsque je dois construire le string en plusieurs étapes avant de le passer au constructeur de Contenu. Ainsi, si je fais ce traitement dans le corps du constructeur, je ne sais pas si mon objet "Contenu" a deja été initialisé (Je suppose que oui avec le constructeur "par défaut") et/ou comment appeler son constructeur correctement une fois que j'ai réussi à construire mon string.

    En bref, la question basique c'est "Comment appeler correctement le constructeur de l'objet "Contenu", dans le corps du constructeur de "Contenant". Pour une fois je prefererais eviter d'utiliser un pointeur et de gerer l'objet en memoire dynamique.

    Un exemple ci-dessous ou l'on voudrait concatener le compteur d'instance à la chaine de "Contenant" avant de la passer au constructeur de "Contenu".

    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
    class CContenu
    {
    private:
     
        std::string m_message;
     
    public:
     
        CContenu()
        :m_message(std::string("Par defaut"))
        {}
     
        CContenu(std::string message)
        :m_message(message)
        {}
    }
     
    class CContenant
    {
    private:
     
        static int compteur_instance;
     
        CContenu m_contenu;
     
    public:
     
        // Premier exemple ou on ne fait que passer le message au contenu, pas de souci
        CContenant(std::string message)
        :m_contenu(message)
        {
            CContenant::compteur_instance++;
        }
    }
     
    // initialisation de la variable statique
    CContenant::compteur_instance=0;
    Or si je veux concatener à "message" la valeur de compteur_instance, je dois, je pense faire quelque chose du style :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    ostringstream oss;
    oss << CContenant::compteur_instance;
    std::string messageFinal=message+oss.str();
    Or je ne pense pas pouvoir faire ca dans la liste d'initialisation.
    Donc, si je le met dans le corps du constructeur, comment faire pour initialiser m_contenu avec messageFinal ?

    Merci d'avance pour votre aide et désolé de poser une question si basique mais je crois que mes cours de C++ sont trop loins derrière moi...

    B.

  2. #2
    screetch
    Invité(e)
    Par défaut
    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
    class CContenu
    {
    private:
     
        std::string m_message;
     
    public:
     
        CContenu()
        :m_message(std::string("Par defaut"))
        {}
     
        CContenu(std::string message)
        :m_message(message)
        {}
    }
     
    class CContenant
    {
    private:
     
        static int compteur_instance;
     
        CContenu m_contenu;
     
        static std::string buildMessage(const std::string& prefix)
        {
            ostringstream oss;
            oss << compteur_instance;
            return=message+oss.str();
        }
    public:
        CContenant(const std::string& message)
        :m_contenu(buildMessage(message))
        {
            CContenant::compteur_instance++;
        }
    }
     
    // initialisation de la variable statique
    CContenant::compteur_instance=0;

  3. #3
    Membre à l'essai
    Profil pro
    Inscrit en
    Juin 2004
    Messages
    37
    Détails du profil
    Informations personnelles :
    Âge : 40
    Localisation : France

    Informations forums :
    Inscription : Juin 2004
    Messages : 37
    Points : 19
    Points
    19
    Par défaut
    Ok je vois... Simple et efficace, je ne savais pas qu'on pouvait faire appel a une fonction statique dans la liste d'init.
    Dommage que cela alourdisse la definitin de la classe cela dit.

    Au passage je note la modif pour passer par adresse le message

    Merci pour ta réponse !

    C'est l'unique façon de faire ? Et surtout c'est une pratique courante ?

  4. #4
    screetch
    Invité(e)
    Par défaut
    Ca pourrait etre une methode libre (mais alors tu ne pourrais pas utiliser la variable statique) ce qui permet de ne pas alourdir la classe.

    Ici le code est inliné par simplicité, normalement on ne verrait que la declaration.

    Moi je fais souvent comme ca mais bon, je force personne a faire de même

  5. #5
    Membre à l'essai
    Profil pro
    Inscrit en
    Juin 2004
    Messages
    37
    Détails du profil
    Informations personnelles :
    Âge : 40
    Localisation : France

    Informations forums :
    Inscription : Juin 2004
    Messages : 37
    Points : 19
    Points
    19
    Par défaut
    Eheh ok merci, alors je vais m'employer a appliquer cette solution dans mon code.

  6. #6
    Membre éclairé
    Avatar de Ekleog
    Homme Profil pro
    Étudiant
    Inscrit en
    Janvier 2012
    Messages
    448
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Janvier 2012
    Messages : 448
    Points : 879
    Points
    879
    Par défaut
    Une autre solution plus réutilisable :
    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
    // Partie réutilisable, dans un fichier helpers.hpp ?
    std::string int2str(int i) {
        std::ostringstream oss;
        oss << i;
        return oss.str()
    }
     
    // Partie utilisation
    class CContenant
    {
    private:
        static int compteur_instance;
        CContenu m_contenu;
     
    public:
        CContenant(std::string message)
            : m_contenu(int2str(compteur_instance) + message)
        {
            CContenant::compteur_instance++;
        }
    };
     
    CContenant::compteur_instance=0;

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

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 627
    Points : 30 692
    Points
    30 692
    Par défaut
    Salut,

    Moi, il y a un truc qui me chipote réellement

    Pourquoi avoir un membre de classe compteur_instance statique dans CContenant

    Je ne dis pas que c'est faux (tout dépend de la manière dont tu manipule ton contenu et ton contenant ) mais, en tout état de cause, je vois de très sérieux problèmes tels que tu présente ta classe contenant re

    Je m'explique:

    Tel que ta classe CContenant est présentée, tu vas compter qu'il y a une instance de CContenant de plus chaque fois que tu vas créer explicitement un objet de ce type, c'est à dire, sous une forme proche de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    int main()
    {
        CContenant contenant1(/* paramètre */);  // compteur_instance est incrémenté
        CContenant * ptr = new CContenant(/* paramètre */); // compteur_instance est incrémenté
     
    }
    Soit!

    A priori, je n'ai rien contre cela ... Quoi que...

    Comme tu ne prend pas la peine de décrémenter le compteur lorsque ton objet de type CContenant est détruit, je me demande déjà bel et bien à quoi ce compteur peut servir !!! re re

    En effet, il faut penser que tout objet créé sera (ou devrait être, si l'on a recours à l'allocation dynamique de la mémoire ) détruit à un moment ou à un autre!!! Nous avons donc en fait affaire à
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    int main()
    {
        CContenant * ptr ; // compteur_instance ne bouge pas ;)
        {
              CContenant obj(/* parametre */ ); // compteur_instance est incrémenté
              ptr = new CContenant(/* paramètre */) ;  // compteur_instance est incrémenté
        } // obj est détruit, mais  compteur_instance  ne bouge pas !!!
        delete ptr ; // ptr est détruit, mais  compteur_instance  ne bouge pas !!!
        std::cout<<CContenant::compteur_instance<< std::endl; // Affichera 2
        return 0;
    }
    Mon optimisme aidant, je me dis que, après tout, si ton idée est de savoir combien d'objet de type CContenant ont été construits, tu atteints malgré tout ton objectif.

    Oui, mais bon... je n'arrive pas à rester optimiste bien longtemps car, comme tu ne nous dis pas exactement ce que tu souhaites, je ne peux m'empêcher de penser que, si ton but est d'entreprendre une action particulière quand toutes tes instances de Ccompteur sont détruites, il faudrait pouvoir au minimum constater que c'est le cas, et donc, faire en sorte que compteur_instance soit... décrémenté chaque fois qu'un objet de type CContenant est effectivement détruit (que ce soit de manière implicite ou explicite).

    Et, à ce point de la réflexion, je me rend compte que, si tu envisages l'incrémentation du compteur d'instance chaque fois que tu crées un objet de type CContenant de manière explicite, tu ne nous dis absolument pas si ta classe de type CContenant est copiable et / ou affectable, ou si elle ne l'est pas !!

    Et du coup, je m'emballe dans mes réflexions :

    Comme tu ne déclares pas le destructeur de CContenant comme étant virtuel ni comme étant protégé, j'en déduis que CContenant n'a pas vocation à être dérivé (comprend: à servir de classe de base à d'autres classes), et donc que c'est une classe qui a, peu ou prou, sémantique de valeur (deux instances "identiques" de la classes peuvent apparaitre à différents endroits de la mémoire).

    Oui, mais, si CContenant a sémantique de valeur, cela rend la classe copiable!!! Or, tu ne tiens absolument pas compte, dans ton comptage de références, du fait qu'une copie peut survenir, ce qui rend ton comptage de référence inutile, vu que tu ne comptes qu'une partie seulement des objets qui seront créés (re re re )

    L'autre possibilité n'est guère plus convaincante, car, je me dis que l'alternative est que CContenant soit une classe ayant sémantique d'entité (chaque fois qu'un objet peut etre considéré comme identique à un autre, c'est que les deux objets utilisent la même adresse en mémoire), mais, dans ce cas, ta classe ne devrait être ni copiable, ni assignable : l'utilisation de la construction par copie et de l'opérateur d'affectation ( operator = ) devraient être explicitement interdite... et ce n'est pas le cas

    Au final, je me dis que l'on manque vraiment d'information pour savoir si le compteur d'instance est vraiment utile, et je me demande si tu as déjà réfléchi correctement à ce que tu voulais faire

    La première question concrète qui me vient à l'esprit est "as tu réellement besoin d'un compteur d'instance qui soit partagé par l'ensemble des objets de type CContenant "

    Si tu en viens à répondre "oui" à cette question (je te l'ai dit, je n'ai, a priori, aucun problème à ce que tu réponde oui à cette question ), il faut déterminer si ta classe CContenant est copiable, ou non.

    Si elle est copiable, il faut veiller à ce que le compteur d'instances soit incrémenté également lors de la copie, et, si elle ne l'est pas, il faut explicitement interdire la copie

    Et, quoi qu'il en soit, il me semble important de définir clairement l'objectif que tu poursuis en mettant ce comptage de références en place de manière à déterminer s'il est utile ou non de veiller à décrémenter le compteur lorsqu'un objet de type CContenant est détruit

    PS: je sais que cette réponse n'apporte rien à ton problème d'origine, mais les réponses qui ont été données me semblent "suffisamment correctes" pour ne pas revenir dessus. Par contre, je ne peux que t'inciter à réfléchir à ma prose

Discussions similaires

  1. Réponses: 2
    Dernier message: 21/01/2015, 19h29
  2. Réponses: 3
    Dernier message: 06/07/2007, 09h17
  3. Réponses: 4
    Dernier message: 20/07/2006, 10h35
  4. Réponses: 3
    Dernier message: 13/06/2006, 16h36
  5. [VBA] utiliser une macro contenue dans un autre classeur
    Par laloune dans le forum Macros et VBA Excel
    Réponses: 20
    Dernier message: 01/02/2006, 18h46

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