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 :

Besoin d'aide pour comprendre l'appel au constructeur et destructeur de classe dans tableau d'objet


Sujet :

Langage C++

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

    Informations forums :
    Inscription : Juin 2010
    Messages : 34
    Points : 20
    Points
    20
    Par défaut Besoin d'aide pour comprendre l'appel au constructeur et destructeur de classe dans tableau d'objet
    Bonjour a tous,

    Je suis en train de coder un tableaux qui stocke des objet de classeD, a chaque ajout ce tableau s'elargit et stocke mon nouvel élément dans une nouvelle case.
    Mais avant d'arriver a ce stade, je souhaite comprendre le comportement qui se produit actuellement dans mon programme (je fais ici un test avec un tableaux définis de base comportant une ligne et une colonne).

    Voici mes fichiers :
    classD.hpp
    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
    #ifndef CLASSD_HPP
    #define CLASSD_HPP
    #include <string>
     
    using namespace std;
     
    class classD
    {
        public:
            classD(const string myName = "classD");
            classD(const classD& aclassD);
            ~classD();
            string Getname() { return _name; }
            void Setname(string val) { _name = val; }
        private:
            string _name;
    };
     
    #endif // CLASSD_HPP
    classD.cpp
    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
    #include <iostream>
    #include "classD.hpp"
     
    // Classe classD
     
    classD::classD(const string myName){
            _name = myName;
            cout<<"Creation d'un objet de classD de nom : "<<_name<<endl;
    }
     
    classD::classD(const classD& aclassD){
        _name = aclassD._name;
    }
     
    classD::~classD(){
            cout<<"Destruction d'un objet de classD de nom : "<<_name<<endl;
        }; //destructeur
    classT.hpp
    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
    #ifndef CLASST_HPP
    #define CLASST_HPP
    #include "classD.hpp"
     
     
    class classT
    {
       public:
            classT(string name="");
            ~classT();
            classD** Get_tab2D() { return _tab2D; }
            void Set_tab2D(classD** val) { _tab2D = val; }
            int Getcolonnes() { return _colonnes; }
            void Setcolonnes(int val) { _colonnes = val; }
            int ajouterElement(const string aName = "ObjectD Tableau");
            classD retournerCase(const int colonne , const int ligne = 0 )const{return _tab2D[ligne][colonne];}
        private:
            classD** _tab2D;
            int _colonnes;
            int LIGNE;
    };
     
    #endif // CLASST_HPP
    classT.cpp
    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
    #include <iostream>
    #include "classT.hpp"
    #include <string>
     
    using namespace std;
     
    classT::classT(string name)
    {
        _colonnes = 0;
        LIGNE = 1;
        //_tab2D = new classD* [_colonnes];
        cout<<"creation objet classe T : "<<name<<endl;
    }
     
    classT::~classT()
    {
        for (int i = 0; i< _colonnes;i++){
            delete _tab2D[i];
            cout<<"destruction objet classe T : colonne ["<<i<<"]"<<endl;
        }
        delete _tab2D;
        cout<<"destruction objet classe T "<<endl;
    }
     
    int classT::ajouterElement(const string aName){
        _colonnes++;
        classD aClassD(aName);
        _tab2D = new classD* [LIGNE];
        _tab2D[0] = new classD[_colonnes];
        _tab2D[0][0] = aClassD;
        return 0;
    }
    Et finalement mon fichier main

    main.cpp
    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 <iostream>
    #include "fonctions.hpp"
     
    int main()
    {
    //#########theme 3
    cout<<endl<<"#########theme 3"<<endl<<endl;
    //Tableau 2D
        classT monTabT("mon TabT");
        monTabT.ajouterElement("Mon premier objetTab1"); //il n'est possible de n'ajouter qu'un element du fait que _tab2D ne comporte pour l'instant qu'une case
        classD plop = monTabT.retournerCase(0,0);
        cout<<"recupere case[0][0] : "<<plop.Getname()<<endl;
     
        cout<<"-----Destruction instance de classe statique-----"<<endl;
     
        return 0;
     
    }
    Invite de commande
    #########theme 3

    creation objet classe T : mon TabT
    Creation d'un objet de classD de nom : Mon premier objetTab1 // creation de mon objet de type classD a stocker
    Creation d'un objet de classD de nom : classD
    Destruction d'un objet de classD de nom : Mon premier objetTab1 // destruction (pas normal)o_0 de mon objet de type classD a stocker
    recupere case[0][0] : Mon premier objetTab1 // La destruction ci dessus n'a pas detruit l'objet stocker dans le tableau TabT
    -----Destruction instance de classe statique-----
    Destruction d'un objet de classD de nom : Mon premier objetTab1 // destruction de mon objet de type classD a stocker
    Destruction d'un objet de classD de nom : Mon premier objetTab1 // destruction o_0 de mon objet de type classD a stocker
    destruction objet classe T : colonne [0]
    destruction objet classe T

    Process returned 0 (0x0) execution time : 0.371 s
    Press any key to continue.
    Je ne comprend pas pourquoi le constructeur de la classeD est appeler plusieurs fois alors que seul un objet de type ClassD doit etre stocké dans le tableau.
    Merci d'avance pour votre aide.

  2. #2
    Rédacteur/Modérateur


    Homme Profil pro
    Network game programmer
    Inscrit en
    Juin 2010
    Messages
    7 115
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : Canada

    Informations professionnelles :
    Activité : Network game programmer

    Informations forums :
    Inscription : Juin 2010
    Messages : 7 115
    Points : 32 963
    Points
    32 963
    Billets dans le blog
    4
    Par défaut
    Bonjour,


    le code
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    classD aClassD(aName);
        _tab2D = new classD* [LIGNE];
        _tab2D[0] = new classD[_colonnes];
        _tab2D[0][0] = aClassD;
    Va
    - créer aClassD
    - créer _colonnes classD et faire autant d'appel au constructeur par défaut
    - utiliser l'opérateur d'affection sur _tab2D[0][0] avec aClassD comme paramètre
    - aClassD sera supprimé à la fin de la fonction
    --> c'est une copie de aClassD qui a été affecté et survit dans le tableau
    Pensez à consulter la FAQ ou les cours et tutoriels de la section C++.
    Un peu de programmation réseau ?
    Aucune aide via MP ne sera dispensée. Merci d'utiliser les forums prévus à cet effet.

  3. #3
    Expert confirmé
    Homme Profil pro
    Étudiant
    Inscrit en
    Juin 2012
    Messages
    1 711
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Juin 2012
    Messages : 1 711
    Points : 4 442
    Points
    4 442
    Par défaut
    Tu devrais utiliser des vector au lieu de gérer toi même ton tableau.

    Sinon,
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    int classT::ajouterElement(const string aName){
        _colonnes++;
        classD aClassD(aName); // création d'un objet classD
        _tab2D = new classD* [LIGNE];
        _tab2D[0] = new classD[_colonnes]; // création de _colonnes objets classD par defaut
        _tab2D[0][0] = aClassD; // operator=
        return 0; // suppression de aClassD
    }
    Ici tu crée un objet classD temporaire qui est détruit lorsque la fonction se termine.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    classD retournerCase(const int colonne , const int ligne = 0 )const{return _tab2D[ligne][colonne];}
    // création et retour d'une copie
    De même quand tu récupères l'objet dans ton tableau, tu en récupères une copie.
    Met un cout dans le constructeur par copie de classD ça apparaîtra plus clairement.

    edit: correction de ma confusion entre operator= et construction par copie

  4. #4
    Membre expert
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2011
    Messages
    739
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Juin 2011
    Messages : 739
    Points : 3 627
    Points
    3 627
    Par défaut
    Salut,

    lorsque que tu crées le tableau avec new, il y a autant de classD créer que de cellule dans le tableau, ici 1. Ensuite tu modifies la valeur de la première cellule en créant une nouvelle classD, ce qui fait 2 construction.

    Sinon il y a plein de copie d'objet, notamment les std::string qui ne sont pas passés par référence constante.
    Il en va de même pour le prototype de retournerCase qui gagnerait à retourner une référence constante
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    const classD& retournerCase(const int colonne , const int ligne = 0 )const;
    Il y a aussi des fuites mémoire via une mauvaise utilisation de delete. Un new [] demande un delete [].

  5. #5
    Membre à l'essai
    Profil pro
    Inscrit en
    Juin 2010
    Messages
    34
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2010
    Messages : 34
    Points : 20
    Points
    20
    Par défaut
    Merci pour votre réponse je comprend mieux maintenant ce qui se passe dans le premier cas.
    Par contre je ne comprend toujours pourquoi il y a une double destruction de l'objet D "Mon premier objetTab1 ".

    -----Destruction instance de classe statique-----
    Destruction d'un objet de classD de nom : Mon premier objetTab1 // destruction de mon objet de type classD a stocker
    Destruction d'un objet de classD de nom : Mon premier objetTab1 // destruction o_0 de mon objet de type classD a stocker
    destruction objet classe T : colonne [0]
    destruction objet classe T
    Merci

  6. #6
    Expert confirmé
    Homme Profil pro
    Étudiant
    Inscrit en
    Juin 2012
    Messages
    1 711
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Juin 2012
    Messages : 1 711
    Points : 4 442
    Points
    4 442
    Par défaut
    retournerCase te retourne une copie de l'objet (que tu stockes dans plop)

    Quand main retourne, plop et monTabT sont supprimés (monTabT détruit l'objet classD qu'il contient) -> 2 appels au destructeur.

  7. #7
    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 : 49
    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
    Dans ce genre de code de test, ne jamais oublier d'instrumenter aussi le constructeur de copie...
    Ma session aux Microsoft TechDays 2013 : Développer en natif avec C++11.
    Celle des Microsoft TechDays 2014 : Bonnes pratiques pour apprivoiser le C++11 avec Visual C++
    Et celle des Microsoft TechDays 2015 : Visual C++ 2015 : voyage à la découverte d'un nouveau monde
    Je donne des formations au C++ en entreprise, n'hésitez pas à me contacter.

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

    Informations forums :
    Inscription : Juin 2010
    Messages : 34
    Points : 20
    Points
    20
    Par défaut
    Merci pour votre aide, je vais regarder plus en détail mon constructeur de copie.

Discussions similaires

  1. MVC besoin d'aide pour comprendre
    Par damien77 dans le forum Servlets/JSP
    Réponses: 11
    Dernier message: 26/06/2007, 12h17
  2. besoin d'aide pour comprendre un exo simple de java
    Par chadel dans le forum Langage
    Réponses: 2
    Dernier message: 16/03/2007, 23h27
  3. [MySQL] besoin d'aide pour comprendre les injections sql
    Par cassy dans le forum PHP & Base de données
    Réponses: 8
    Dernier message: 28/01/2007, 14h21
  4. Besoin d aide pour comprendre un code
    Par litlebasic dans le forum Delphi
    Réponses: 4
    Dernier message: 22/06/2006, 13h00

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