Précédent   Forum du club des développeurs et IT Pro > C et C++ > C++ > Débuter
Débuter Forum d'entraide pour débuter en langage de programmation C++. Avant de poster : cours d'initiation au C++
Partagez cette discussion sur d'autres réseaux sociaux : Viadeo Twitter Google Facebook Digg Delicious MySpace Yahoo
Réponse
 
Outils de la discussion
Publicité
'
Vieux 03/12/2012, 10h19   #1
Achamian
Invité de passage
 
Homme
Étudiant
Inscription : décembre 2012
Messages : 3
Détails du profil
Informations personnelles :
Sexe : Homme

Informations professionnelles :
Activité : Étudiant

Informations forums :
Inscription : décembre 2012
Messages : 3
Points : 0
Points : 0
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 :
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 :
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 !
Achamian est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 03/12/2012, 10h47   #2
leternel
Expert Confirmé
 
Homme Pierre
Ingénieur développement logiciels
Inscription : juin 2007
Messages : 1 368
Détails du profil
Informations personnelles :
Nom : Homme Pierre
Localisation : France

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

Informations forums :
Inscription : juin 2007
Messages : 1 368
Points : 2 903
Points : 2 903
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 :
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 :
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 :
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 :
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.
  • La plus sotte des questions est celle qu'on ne pose pas.
Pour faire des graphes, essayez yEd.
leternel est actuellement connecté   Envoyer un message privé Réponse avec citation 10
Vieux 04/12/2012, 01h15   #3
Achamian
Invité de passage
 
Homme
Étudiant
Inscription : décembre 2012
Messages : 3
Détails du profil
Informations personnelles :
Sexe : Homme

Informations professionnelles :
Activité : Étudiant

Informations forums :
Inscription : décembre 2012
Messages : 3
Points : 0
Points : 0
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 ?
Achamian est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 04/12/2012, 06h57   #4
Neckara
Rédacteur/Modérateur

 
Avatar de Neckara
 
Homme Denis
Étudiant
Inscription : décembre 2011
Messages : 2 841
Détails du profil
Informations personnelles :
Nom : Homme Denis
Localisation : France, Loire (Rhône Alpes)

Informations professionnelles :
Activité : Étudiant

Informations forums :
Inscription : décembre 2011
Messages : 2 841
Points : 8 629
Points : 8 629
Envoyer un message via MSN à Neckara Envoyer un message via Skype™ à Neckara
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 :
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.
__________________
Recherche devs C++ motivés et sérieux pour Last Dungeon.

Chaîne Youtube : Vidéos

Ma page DVP : http://neckara.developpez.com/
Neckara est actuellement connecté   Envoyer un message privé Réponse avec citation 10
Vieux 04/12/2012, 10h50   #5
leternel
Expert Confirmé
 
Homme Pierre
Ingénieur développement logiciels
Inscription : juin 2007
Messages : 1 368
Détails du profil
Informations personnelles :
Nom : Homme Pierre
Localisation : France

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

Informations forums :
Inscription : juin 2007
Messages : 1 368
Points : 2 903
Points : 2 903
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 :
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.
  • La plus sotte des questions est celle qu'on ne pose pas.
Pour faire des graphes, essayez yEd.
leternel est actuellement connecté   Envoyer un message privé Réponse avec citation 00
Vieux 04/12/2012, 23h36   #6
JolyLoic
Rédacteur/Modérateur
 
Avatar de JolyLoic
 
Homme Loïc Joly
Développeur informatique
Inscription : août 2004
Messages : 4 699
Détails du profil
Informations personnelles :
Nom : Homme Loïc Joly
Âge : 38
Localisation : France

Informations professionnelles :
Activité : Développeur informatique
Secteur : High Tech - Éditeur de logiciels

Informations forums :
Inscription : août 2004
Messages : 4 699
Points : 9 968
Points : 9 968
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.
JolyLoic est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 05/12/2012, 08h17   #7
MicBeastKiller
Membre du Club
 
Inscription : juin 2008
Messages : 121
Détails du profil
Informations forums :
Inscription : juin 2008
Messages : 121
Points : 63
Points : 63
Récursif est-il le bon terme ?
Ne cherches-tu pas plutôt à faire ceci :
Code :
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;
        }
    }
};
MicBeastKiller est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 09/12/2012, 11h06   #8
Achamian
Invité de passage
 
Homme
Étudiant
Inscription : décembre 2012
Messages : 3
Détails du profil
Informations personnelles :
Sexe : Homme

Informations professionnelles :
Activité : Étudiant

Informations forums :
Inscription : décembre 2012
Messages : 3
Points : 0
Points : 0
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.
Achamian est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 09/12/2012, 15h40   #9
droggo
Expert Confirmé
 
Inscription : août 2006
Messages : 3 433
Détails du profil
Informations forums :
Inscription : août 2006
Messages : 3 433
Points : 3 808
Points : 3 808
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 ).
__________________
Il court en ce moment une espèce de grippe, mais elle ne court pas très vite, car on peut l'attraper sans courir.
droggo est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 10/12/2012, 10h40   #10
Bousk
Modérateur
 
Homme Cyrille
Network programmer
Inscription : juin 2010
Messages : 1 570
Détails du profil
Informations personnelles :
Nom : Homme Cyrille
Âge : 25
Localisation : France

Informations professionnelles :
Activité : Network programmer

Informations forums :
Inscription : juin 2010
Messages : 1 570
Points : 4 156
Points : 4 156
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.
Bousk est déconnecté   Envoyer un message privé Réponse avec citation 00
Réponse
Outils de la discussion

Navigation rapide


Fuseau horaire GMT +2. Il est actuellement 12h46.


 
 
 
 
Partenaires

Hébergement Web