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 :

Appel récursif au constructeur : double erreur


Sujet :

C++

  1. #1
    Nouveau Candidat au Club
    Homme Profil pro
    Étudiant
    Inscrit en
    Décembre 2012
    Messages
    3
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Décembre 2012
    Messages : 3
    Points : 1
    Points
    1
    Par défaut Appel récursif au constructeur : double erreur
    Bonjour,

    J'ai commencé le C++ il y a peu et j'ai rencontré un petit problème en essayant d'appeler un constructeur en récursif :

    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
    class Sinus {
     
        int MU;
        public:
        Sinus(){MU=1;}
        Sinus(int mu){
     
            if(mu==0){
                int m;
                cout<<"Autre nombre"<<endl;
                cin>>m;
                Sinus(m);
     
                }
            else{
                MU = mu;
                }
            }
    };
    Ce code n'a même pas compilé, j'ai donc modifié le code comme ceci :

    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
    class Sinus {
    
        int MU;
        public:
        Sinus(){MU=1;}
        Sinus(int mu){
            int m;
            if(mu==0){
                cout<<"Autre nombre"<<endl;
                cin>>m;
                Sinus(m);
    
                }
            else{
                MU = mu;
                }
            }
    };
    Ce programme compile sans problème, mais si l'utilisateur entre 0, je récupère un mauvais MU (MU = 200895864).
    J'ai donc deux questions :
    -Pourquoi le 1e code ne compile pas ?
    -Pourquoi le second me renvoie un mauvais MU ?

    Merci d'avance !

  2. #2
    Expert éminent sénior

    Femme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2007
    Messages
    5 189
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Localisation : France, Essonne (Île de France)

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

    Informations forums :
    Inscription : Juin 2007
    Messages : 5 189
    Points : 17 141
    Points
    17 141
    Par défaut
    Un constructeur n'est jamais récursif.

    L'appel d'un constructeur crée une valeur de ce type, même depuis le code d'un autre constructeur.

    Pour initier une valeur pendant la construction, la syntaxe est:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    class s {
    private:
        int m;
    public:
        s(int value) : m(value) {}
    };
    Pour modifier la valeur une fois l'objet construit, on utilise une affectation classique.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    class s {
    private:
        int* m;
    public:
        s(int value) : m(std::nullptr) {
            m = new int*;
            *m = value;
        }
    };
    Donc pour moi, ta classe devrait être
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    class Sinus {
    private:
        int MU;
    public:
        Sinus():MU(1){}
     
        Sinus(int mu): MU(mu){
            while (mu==0){
                cout <<"Autre nombre"<<endl;
                cin>>mu;
            }
        }
    };
    voire même, par le truchement des arguments par défaut et de la gestion d'exception:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    class Sinus {
    private:
        int MU;
    public:
        Sinus(int mu = 1) : MU(mu) {
            if (MU==0) throw std::invalid_argument("Sinus(0) is invalid");
        }
    };
    Mes principes de bases du codeur qui veut pouvoir dormir:
    • Une variable de moins est une source d'erreur en moins.
    • Un pointeur de moins est une montagne d'erreurs en moins.
    • Un copier-coller, ça doit se justifier... Deux, c'est un de trop.
    • jamais signifie "sauf si j'ai passé trois jours à prouver que je peux".
    • La plus sotte des questions est celle qu'on ne pose pas.
    Pour faire des graphes, essayez yEd.
    le ter nel est le titre porté par un de mes personnages de jeu de rôle

  3. #3
    Nouveau Candidat au Club
    Homme Profil pro
    Étudiant
    Inscrit en
    Décembre 2012
    Messages
    3
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Décembre 2012
    Messages : 3
    Points : 1
    Points
    1
    Par défaut
    Merci pour ta réponse !

    Mon professeur m'a affirmé, pendant que je postais ce code sur le forum, qu'un appel à un constructeur en récursif était possible car c++ ne créait ainsi qu'un seul objet (il m'en a d'ailleurs fait plusieurs exemples concluants).

    Que se passe t-il lorsque l'on appelle un constructeur récursivement ? Y-a t-il des conditions à respecter si l'on veut appeler un constructeur en récursif ou est-ce à bannir définitivement ?

  4. #4
    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 Achamian Voir le message
    Mon professeur m'a affirmé, pendant que je postais ce code sur le forum, qu'un appel à un constructeur en récursif était possible car c++ ne créait ainsi qu'un seul objet (il m'en a d'ailleurs fait plusieurs exemples concluants).
    J'ai un gros doute là-dessus.
    Peux-tu nous montrer vos "exemples" ?

    Si tu fait :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    C::C(int i)
    {
             if(i)
               C(--i);
    }
    Tu va créer des objets temporaires qui seront détruits dès la fin de la ligne et je ne vois pas trop l'intérêt de faire ça à par tenter de rendre le code plus obscur.
    Si on veut créer plusieurs instances de C, on utilisera une factory.

  5. #5
    Expert éminent sénior

    Femme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2007
    Messages
    5 189
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Localisation : France, Essonne (Île de France)

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

    Informations forums :
    Inscription : Juin 2007
    Messages : 5 189
    Points : 17 141
    Points
    17 141
    Par défaut
    Regarde toute la section constructeurs de la faq.

    Il faut comprendre qu'un constructeur est constitué de plusieurs choses très distinctes, et que ce qu'on appellerai "constructeur récursif" est forcément impossible pour cette raison même.

    Supposons la classe suivante:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    class s {
    private:
        int m;
    };
    Le constructeur aura la forme suivante: signature : construction {initialisation} c'est à dire S::s(int value) : m(value) {}La partie construction est un ensemble d'appels aux constructeurs de chaque membre, classe mère et classe virtuelle mère.
    Les types de bases utilisent la même notation, par exemple: m(2)Chaque membre ne peut être construit qu'une fois, ils sont construit dans l'ordre d'instanciation par la classe. (plus d'informations)
    Les membres non explicitement construits utilisent leur constructeur par défaut (pointeur et type de bases utilisent en théorie 0, mais mieux vaut les spécifier).

    La partie initialisation est appelée une fois l'objet construit. Elle permet de modifier l'objet pour le placer dans un état valide.
    Le constructeur ne peut pas appeler un constructeur récursivement, parce quand on voudrait le faire, l'objet est déjà construit, et on est en train de l'initialiser.

    Par contre, il existe des arguments par défaut, qui permettent de regrouper plusieurs constructeurs en un seul.

    Dans tous les cas, un appel au constructeur qui ne parvient pas à se terminer à cause d'une exception (d'où quelle vienne) provoque la désallocation immédiate de l'objet.
    Le destructeur de l'objet n'est pas appelé (puisqu'il n'est pas pleinement construit), par contre tout membre construit au moment de l'exception est bien détruit.
    Mes principes de bases du codeur qui veut pouvoir dormir:
    • Une variable de moins est une source d'erreur en moins.
    • Un pointeur de moins est une montagne d'erreurs en moins.
    • Un copier-coller, ça doit se justifier... Deux, c'est un de trop.
    • jamais signifie "sauf si j'ai passé trois jours à prouver que je peux".
    • La plus sotte des questions est celle qu'on ne pose pas.
    Pour faire des graphes, essayez yEd.
    le ter nel est le titre porté par un de mes personnages de jeu de rôle

  6. #6
    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
    A noter qu'il est possible en C++11 qu'un constructeur en appelle un autre (c'est connu sous le nom de delegating constructors), mais ça ne permet en aucun cas des appels récursifs.
    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.

  7. #7
    Membre régulier
    Inscrit en
    Juin 2008
    Messages
    140
    Détails du profil
    Informations forums :
    Inscription : Juin 2008
    Messages : 140
    Points : 103
    Points
    103
    Par défaut
    Récursif est-il le bon terme ?
    Ne cherches-tu pas plutôt à faire ceci :
    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
     
    class Sinus
    {
        int MU;
        public:
        Sinus(): MU( 1 )
        {
     
        }
        Sinus( int mu ): MU( mu )
        {        
            if( mu == 0 )
            {
                cout << "Autre nombre: " << endl;
                cin >> MU;
            }
        }
    };

  8. #8
    Nouveau Candidat au Club
    Homme Profil pro
    Étudiant
    Inscrit en
    Décembre 2012
    Messages
    3
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Décembre 2012
    Messages : 3
    Points : 1
    Points
    1
    Par défaut
    Neckara, je n'ai plus ces exemples en tête, je redemanderai à mon prof demain si je le vois.

    leternel, merci pour toutes ces informations sur les constructeurs, je lirai plus attentivement la FAQ sur le sujet. Ce que j'en conclus d'important, c'est qu'ils vaut mieux faire les opérations délicates hors du constructeur.

    MicBeast, oui la question portait sur le récursif. Je n'aurai eu aucun mal à faire un programme qui fonctionne, j'étais simplement curieux de savoir en quoi il ne fonctionnait pas.

  9. #9
    Expert confirmé

    Inscrit en
    Août 2006
    Messages
    3 942
    Détails du profil
    Informations forums :
    Inscription : Août 2006
    Messages : 3 942
    Points : 5 654
    Points
    5 654
    Par défaut
    Koa,

    À mon avis, vouloir faire un constructeur récursif montre une profonde méconnaissance de ce qu'est un constructeur, et si c'est un prof qui a suggéré ça, il faut en changer immédiatement (je sais, je sais : tu n'as pas pas le choix ).
    Si les cons volaient, il ferait nuit à midi.

  10. #10
    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 seul moment où tu fais un appel explicite au constructeur c'est dans le cas d'un héritage où la classe mère a un constructeur avec paramètres.
    Sinon, tu n'as pas à te soucier d'appeler le constructeur, c'est automatique à la création d'un objet.
    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.

Discussions similaires

  1. Réponses: 12
    Dernier message: 13/10/2007, 11h37
  2. Appel d'un constructeur à partir d'un autre
    Par Pragmateek dans le forum Langage
    Réponses: 28
    Dernier message: 18/06/2006, 01h07
  3. Réponses: 5
    Dernier message: 29/04/2006, 21h41
  4. [onresize] appels récursifs
    Par pmartin8 dans le forum Général JavaScript
    Réponses: 2
    Dernier message: 02/12/2005, 21h15
  5. Appel recursif au constructeur
    Par Math75 dans le forum C++
    Réponses: 1
    Dernier message: 11/10/2005, 15h48

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