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 par défaut appelé après constructeur d'initialisation ?


Sujet :

C++

  1. #1
    Membre régulier
    Profil pro
    Inscrit en
    Juin 2007
    Messages
    128
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations forums :
    Inscription : Juin 2007
    Messages : 128
    Points : 70
    Points
    70
    Par défaut Constructeur par défaut appelé après constructeur d'initialisation ?
    Bonjour,

    Boite et caillou sont deux classes.
    On a la classe Boite :
    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
    class Boite
    {
    private :
    	int taille;
    	int nbMax;
    	Caillou c;
    public :
    	Boite(void)
    	{
    		cout << "Constructeur par defaut de Boite" << endl;
    		setTaille(20);
    		setNbMax(5);
    		setCaillou(c);
    	}
     
    	Boite(int t, int nb, const Caillou& c)
    	{
    		cout << "Constructeur par initialisation de Boite" << endl;
    		setTaille(t);
    		setNbMax(nb);
    		setCaillou(c);
    	}
    	~Boite()
    	{
    		cout << "Destructeur de Boite" << endl;
    	}
     
    	// setters et getters classique dont 3 sont cités plus haut
    }
    Et on a la classe Caillou :
    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
    class Caillou
    {
    private :
    	string couleur;
    public :
    	Caillou(void)
    	{
    		cout << "Constructeur par defaut de Caillou" << endl;
    		setCouleur("jaune");
    	}
     
    	Caillou(string c)
    	{
    		cout << "Constructeur par initialisation de Caillou" << endl;
    		setCouleur(c);
    	}
    	~Caillou()
    	{
    		cout << "Destructeur de Caillou" << endl;
    	}
     
    	// setters et getters classique dont 1 est cité plus haut
    }
    Dans mon programme principal(main), j'effectue ceci :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    Boite b(0, 0, Caillou("bleu"));
    Tout marche à merveille.. Sauf que je me rend compte en traçant le programme qu'il invoque les constructeurs dans cet ordre :
    Constructeur par initialisation de l'objet Caillou
    Constructeur par defaut de l'objet Caillou
    Constructeur par initilisation de l'objet Boite
    Destructeur de l'objet Caillou
    Or, je m'attendais à ce que les constructeurs appelés soient :
    Constructeur par initilisation de l'objet Caillou
    Constructeur par initilisation de l'objet Boite
    Du coup, je ne comprend pas..
    Auriez-vous une idée du soucis(si il y en a un) ?

    Merci.

    ps : Mon programme ne se limite pas à 2 classes. Il s'agit ici d'un extrait complet(tout ce qui est en rapport aux 2 classes y est).


    Edit :
    Je rajoute des infos :
    Quand je fais du pas à pas avec le debugger :
    1] je passe bien par le constructeur d'initialisation de Caillou.
    2] A la fin du constructeur d'initialisation de Caillou, je passe sur la déclaration du constructeur d'initialisation de Boite.
    3] En faisant un step into, je ne me retrouve pas dans le constructeur d'initialisation de Boite mais dans le constructeur par défaut de Caillou.
    4] Dans ce constructeur, il n'y a que des erreurs. Quand j'essaie d'accèder à la mémoire de l'objet et quand je passe sur le setCouleur.
    5] A la fin de ce constructeur, je repasse sur le constructeur d'initialisation de Boite. A la ligne se trouvant après la déclaration du constructeur.
    6] A la fin du constructeur d'initialisation de Boite, je passe au destructeur de Caillou et là erreur.
    > Il est à noter que lors du débogage, il y a des erreurs mais lancer normalement, il n'y a aucune erreur.

  2. #2
    En attente de confirmation mail

    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Août 2004
    Messages
    1 391
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 33
    Localisation : France, Doubs (Franche Comté)

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

    Informations forums :
    Inscription : Août 2004
    Messages : 1 391
    Points : 3 311
    Points
    3 311
    Par défaut
    Bonjour,

    Je t'invite à consulter une FaQ au sujet des listes d'initialisation. Une fois que ce sera fait, essaie de les utiliser dans ton codes, le comportement que tu observes devrait disparaître (du moins changer).

    Sans rentrer dans les détails (qui sont aborder dans les FaQ), quand tu rentres dans le corps d'un constructeur, tous les sous-objets (membres ou hérités) sont déjà créés. Il y a donc un outil qui permet d'indiquer comment les créer juste avant d'entrer dans le corps du constructeur : les listes d'initialisation.

  3. #3
    Membre émérite

    Inscrit en
    Mai 2008
    Messages
    1 014
    Détails du profil
    Informations forums :
    Inscription : Mai 2008
    Messages : 1 014
    Points : 2 252
    Points
    2 252
    Par défaut
    Bonjour,
    En C++ l'ordre de construction dans un constructeur est le suivant :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
     
    Boite(...arguments...)
    //<----
    //  ici construction par défaut des membres de Boite (dont caillou)
    //<----
    {
    // arrivé ici les membres sont construits
    }
    Si tu veux éviter cette construction par défaut il faut utiliser la "liste d'initialisation" ou "initializer list" (mot clé pour google), comme ça :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    Boite(int t_, int nb_, const Caillou& c_) :
    t(t_), nb(nb_), c(c_)
    {
    }
    Dans ce cas c'est le constructeur par copie de caillou qui va être appelé.
    Vu que caillou ne contient que des types basiques ou des types de la lib standard le constructeur par copie généré automatiquement par le compilateur est suffisant, mais si tu veux voir ce qui se passe tu peux rajouter le constructeur par copie suivant dans caillou :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    Caillou(const Caillou& c) : couleur(c.couleur)
    {
       cout << "Constructeur par copie de Caillou" << endl;
    }

  4. #4
    Membre régulier
    Profil pro
    Inscrit en
    Juin 2007
    Messages
    128
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations forums :
    Inscription : Juin 2007
    Messages : 128
    Points : 70
    Points
    70
    Par défaut
    Merci pour vos réponses, ça répond complètement à ma question
    Je ne connaissais pas ce comportement. La faq à cette adresse l'exprime également très bien :
    Dans ce cas, l'expression n'importe quoi provoque la création d'un objet temporaire, et cet objet temporaire est passé à l'opérateur d'assignation de l'objet. Cet objet temporaire est ensuite détruit, ce qui est inefficace.

  5. #5
    Membre régulier
    Profil pro
    Inscrit en
    Juin 2007
    Messages
    128
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations forums :
    Inscription : Juin 2007
    Messages : 128
    Points : 70
    Points
    70
    Par défaut
    J'ai une dernière question.
    J'ai bien saisis le comportement du constructeur, mais il y a quelque chose qui me perturbe.
    Dans mon cas, j'avais ceci :
    Constructeur par initialisation de l'objet Caillou(1)
    Constructeur par defaut de l'objet Caillou(2)
    Constructeur par initilisation de l'objet Boite(3)
    Destructeur de l'objet Caillou(4)
    Le constructeur d'initialisation de caillou est appelé et stocké temporairement.(1)
    Ensuite, il est passé à l'opérateur d'assignation(2).
    Pour terminer sa course en rentrant dans le constructeur de Boite(3).
    Une fois que le constructeur de Boite a fini, l'objet temporaire n'étant plus nécessaire, il est détruit(4).

    Ce qui me perturbe se trouve en (2). Comment se fait-il que ce soit le constructeur par défaut qui soit appelé ?
    Je sais maitenant qu'avec une liste d'initialisation, comme celle d'Arzar(c(_c)), ce serait le constructeur par copie qui serait appelé à la place de celui par défaut.
    Mais, sans liste d'initialisation, cela veut-il dire que, si je fais Caillou x = y ? :
    * Le programme va créer un objet Caillou en utilisant le constructeur par défaut
    * Le programme va initialiser le nouveau Caillou en faisant une copie membre à membre de y vers *this.
    * Le programme va dire que x = *this

    Merci.

  6. #6
    En attente de confirmation mail

    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Août 2004
    Messages
    1 391
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 33
    Localisation : France, Doubs (Franche Comté)

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

    Informations forums :
    Inscription : Août 2004
    Messages : 1 391
    Points : 3 311
    Points
    3 311
    Par défaut
    Arzar a déjà répondu sur ce point. La liste d'initialisation existe toujours pour l'ensemble des sous-objets qui existent. Si tu ne précises rien pour un sous-objet, alors l'initialisation se fait par défaut, ce qui était ton cas. Si tu indiques explicitement, alors il y aura initialisation par copie.

  7. #7
    Membre régulier
    Profil pro
    Inscrit en
    Juin 2007
    Messages
    128
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations forums :
    Inscription : Juin 2007
    Messages : 128
    Points : 70
    Points
    70
    Par défaut
    Merci pour ta réponse.
    Je n'avais pas bien lu Arzar, c'est vrai qu'il l'indique

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

Discussions similaires

  1. Réponses: 3
    Dernier message: 22/03/2011, 12h56
  2. Réponses: 5
    Dernier message: 13/05/2009, 18h22
  3. Réponses: 11
    Dernier message: 25/08/2006, 16h00
  4. Réponses: 5
    Dernier message: 20/11/2005, 11h15
  5. Constructeur par défaut en cas de surcharge
    Par gigi_m dans le forum MFC
    Réponses: 4
    Dernier message: 08/06/2005, 09h58

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