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 :

Comment limiter les appels aux constructeurs des classes mères? [Débutant(e)]


Sujet :

C++

  1. #1
    Membre expérimenté
    Avatar de coyotte507
    Profil pro
    Inscrit en
    Octobre 2006
    Messages
    1 327
    Détails du profil
    Informations personnelles :
    Âge : 34
    Localisation : France

    Informations forums :
    Inscription : Octobre 2006
    Messages : 1 327
    Points : 1 452
    Points
    1 452
    Par défaut Comment limiter les appels aux constructeurs des classes mères?
    Bonjour!

    En fait j'ai des tas de problèmes...

    Dans ma classe dérivée j'ai plusieurs constructeurs. Chacun appelle automatiquement le constructeur de base (c'est pas de ma faute c'est le compilo qui fait ça). De plus, ils appellent tous le constructeur principal de la classe dérivée, qui fait lui-même un appel spécial au constructeur de base:

    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
     
    //Exemple
     
    class Windows : public OS
    {
      public:
        Windows(int, float);
        Windows(float, int);
    }
     
    //constructeur principal
    Windows::Windows (int a, float b)
    {
      /*
        ....
        Est tout le temps appelé car fait l'initialisation
        des membres de la classe
      */
     
      //appelle le constructeur de la classe de base avec certains paramètres
       OS(/* ...*/);
    }
     
    //constructeur secondaire
    Windows::Windows (float a, int b)
    {
      /*
        ....
      */
     
      //appelle le constructeur principal de la classe dérivée
       Windows(/* ...*/);
    }
    Existe - t - il un moyen de limiter les appels au constructeur de la classe de base? La si j'appelle le deuxième constructeur de Windows, j'ai trois appels au constructeur de base...

  2. #2
    Membre expert
    Avatar de hiko-seijuro
    Profil pro
    Inscrit en
    Mai 2004
    Messages
    2 011
    Détails du profil
    Informations personnelles :
    Âge : 40
    Localisation : France

    Informations forums :
    Inscription : Mai 2004
    Messages : 2 011
    Points : 3 065
    Points
    3 065
    Par défaut
    Pourquoi ne pas utiliser les listes d'initialisation ?

    et je pense que ta méthode est douteuse vis a vis des constructeurs car quand appel un constructeur conceptuellement cela créé l'objet donc un constructeur d'un objet qui appel un autre constructeur d'un meme objet ca équivaut dire à un macon d'appeler un autre macon pour construire la maison :s

  3. #3
    Rédacteur
    Avatar de Zavonen
    Profil pro
    Inscrit en
    Novembre 2006
    Messages
    1 772
    Détails du profil
    Informations personnelles :
    Âge : 76
    Localisation : France

    Informations forums :
    Inscription : Novembre 2006
    Messages : 1 772
    Points : 1 913
    Points
    1 913
    Par défaut
    Dans la définition d'un constructeur on peut faire un appel explicite à un constructeur d'une classe parente avec passage de paramètres immédiatement après la liste des paramètres au moyen de l'opérateur :
    Le truc est récursif de sorte que chaque constructeur fait son boulot et rien que son boulot (en général initialiser les variables qui sont propres à sa classe)
    exemple:

    Si la classe CEtudiant est fille de CCitoyen

    CEtudiant::CEtudiant(char * N, char * P, int X):CCitoyen(N,P)
    {Numero=X;}

    Pour le reste même remarque que la précédente concernant un constructeur appelant un autre constructeur de la même classe.

  4. #4
    Membre expérimenté
    Avatar de coyotte507
    Profil pro
    Inscrit en
    Octobre 2006
    Messages
    1 327
    Détails du profil
    Informations personnelles :
    Âge : 34
    Localisation : France

    Informations forums :
    Inscription : Octobre 2006
    Messages : 1 327
    Points : 1 452
    Points
    1 452
    Par défaut
    en fait c'est juste un autre constructeur qui utilise une va_list (voir stdarg)

    L'un est appelé avec dess arguments multiples (...), l'autre avec une liste d'arguments (va_list)

    Le deuxième convertit juste les arguments en liste d'arguments pour le premier constructeur.

    Sinon pour la liste d'intialistaion, je vais y penser, mais ce n'est pas possible pour le constructeur à arguments multiples (...) et ça ne résout pas le problème de l'appel d'un constructeur de la même classe.

    Ce que je voudrait c'est savoir si il est possible d'empecher au compilateur d'appeler automatiquement le constructeur de la classe de base

  5. #5
    Rédacteur
    Avatar de Zavonen
    Profil pro
    Inscrit en
    Novembre 2006
    Messages
    1 772
    Détails du profil
    Informations personnelles :
    Âge : 76
    Localisation : France

    Informations forums :
    Inscription : Novembre 2006
    Messages : 1 772
    Points : 1 913
    Points
    1 913
    Par défaut
    Par défaut, cest le constructeur par défaut de la classe mère qui est appelé.
    De sorte que si vos constructeurs par défaut ne font rien (en dehors d'une réservation mémoire évidemment), les appels en série ne feront rien (qu'une réservation d'espace) et c'est un moindre mal nécessaire de toutes façons.

  6. #6
    Rédacteur
    Avatar de Laurent Gomila
    Profil pro
    Développeur informatique
    Inscrit en
    Avril 2003
    Messages
    10 651
    Détails du profil
    Informations personnelles :
    Âge : 40
    Localisation : France, Moselle (Lorraine)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Avril 2003
    Messages : 10 651
    Points : 15 920
    Points
    15 920
    Par défaut
    Il faut obligatoirement appeler un constructeur de la classe de base (elle doit bien être construite !).

    Ce que tu sembles ne pas savoir, c'est que cet appel doit obligatoirement être fait dans la liste d'initialisation, et que tout appel à un constructeur par la suite ne fera pas ce à quoi tu t'attends : cela va construire un nouvel objet temporaire puis le supprimer aussi sec ; absoluement aucun effet sur ton instance donc.

  7. #7
    Membre expérimenté
    Avatar de coyotte507
    Profil pro
    Inscrit en
    Octobre 2006
    Messages
    1 327
    Détails du profil
    Informations personnelles :
    Âge : 34
    Localisation : France

    Informations forums :
    Inscription : Octobre 2006
    Messages : 1 327
    Points : 1 452
    Points
    1 452
    Par défaut
    Merci Laurent ^^

    et dans ce cas

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    classeH::classeH(int &nbargs, va_list args)
             :classeB(nbargs, args)
    {
    //...
    }
    
    classeH::classeH(int nbargs, ...)
    {
      va_list args;
      va_start(args, nbargs);
      classeH(nbargs, args);
    }
    Est ce que le code en rouge affecte la présente instance? Si oui, le constructeur classeB de la liste d'initialisation du premier constructeur affectera-t'il la présente instance?

    edit:
    Réponses:
    1. Non
    2. Non

  8. #8
    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,

    Déjà, de manière générale, l'utilisation d'une va_list n'est clairement pas conseillée, et elle l'est encore moins en ce qui concerne le constructeur.

    Il faut bien comprendre qu'un constructeur, ca permet d'initialiser un objet, et que, en gros, ca se fait en trois étapes:
    • trouver un endroit en mémoire où l'on a la place suffisante pour tout mettre (sur la pile ou sur le tas, en fonction de si on utilise new ou non)
    • trouver les adresses, dans l'espace mémoire fournis, auxquelles commencent les différentes variables qui composent l'objet
    • fournir une valeur à ces variables

    Ensuite, je conçois mal que l'on puisse faire une pate à crepes, ou construire une maison, sans avoir une idée précise de ce que l'on va mettre dans la pate ou du matériaux que l'on va utiliser pour la maison...

    Pourquoi faire différemment en programmation

    Au pire, rien ne t'empeche de prévoir plusieurs constructeurs distincts:
    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
     
    class MaClasse
    {
        public:
            MaClasse():                 /* constructeur par défaut, toutes les 
            _name("unnamed"){}           * valeurs sont nulles  ou prédéterminées */
            MaClasse(const std::string& nom):/* juste le nom est donné, les autres
            _name(nom){}                      * valeurs sont nulles ou
                                              * prédéterminées */
            MaClasse(const std::string& nom, int i):/* seul j est prédéterminé, on
            _name(nom)                                * fournit un seul "i" */
            {
                 _i.push_back(i);
            }
            MaClasse(const std::string& nom, int i, float j);/* un seul i et 
            _name(nom)                                        * un seul j*/
            {
                _i.push_back(i);
                _j.push_back(j);
            }
            MaClasse(const std::string& nom, std::vector<int> tabi, 
                     std::vector<float> tabj):/* plusieurs "i" et plusieurs "j" */
            _name(nom),_i(tabi),_j(tabj){}
            /* le reste (pourquoi pas d'autres constructeurs si besoin ? */
        private:
            std::string _name;
            std::vector<int> _i;
            std::vector<float> _j;
            /* le reste */
    };
    Une fois que tu as prévu l'ensemble des possibilités de construction de ta classe de base, rien ne t'empeche d'utiliser le constructeur de cette classe "qui va bien" dans les classes dérivée, en fonction des besoin
    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
     
    class Deriv1: public Maclasse
    {
        public:
            Deriv1(const std::string& nom, const std::string& type):Maclasse(nom)
            _type(type){}
        private:
            std::string _type;
    };
    class Deriv2:public MaClasse
    {
        public:
            Deriv2(const std::string& nom, int i, float j, double d):
                MaClasse(nom, i, j), _d(d){/* "surplus éventuel" */}
        private:
           double _d;
    };
    class Deriv3:public MaClasse
    {
        public:
            Deriv3(const std::string& nom, std::vector<int> tabi, 
            std::vector<float> tabj, std::vector<std::string> s):
                Maclasse(nom, tabi,tabj),_s(s){/* "surplus" éventuel */}
        private:
            std::vector<std::string> _s;
    };
    et, s'il se fait que les informations recues - quelle que soit l'origine, mais, de manière générale, via la ligne de commande - sont susceptibles d'être fournies dans le désordre, il s'agira de vérifier ces informations avant l'appel du constructeur, afin, principalement, de s'assurer qu'elles soient valides...

  9. #9
    Membre expérimenté
    Avatar de coyotte507
    Profil pro
    Inscrit en
    Octobre 2006
    Messages
    1 327
    Détails du profil
    Informations personnelles :
    Âge : 34
    Localisation : France

    Informations forums :
    Inscription : Octobre 2006
    Messages : 1 327
    Points : 1 452
    Points
    1 452
    Par défaut
    J'ai bien compris et si nécessaires je mettrais les arguments explicitement dans la déclaration du constructeur.

    Mais:

    Est-il possible d'empêcher un appel au constructeur de base? (en assumant les conséquences)

  10. #10
    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
    La réponse courte tient en un mot: non...

    La réponse complete étant: ou bien, tu a prévu un constructeur par défaut pour ta classe de base, qui sera - d'office - appelé lors de la construction de ton objet de type dérivé, ou bien le compilateur se plaindra de ne pas trouver de constructeur pour la classe de base.

    Il n'y a rien à faire, c'est toujours identique à la vie de tous les jours: si tu construit une maison, les briques que tu va utiliser ont du etre construites, meme si ce n'est pas par toi

  11. #11
    Membre expérimenté
    Avatar de coyotte507
    Profil pro
    Inscrit en
    Octobre 2006
    Messages
    1 327
    Détails du profil
    Informations personnelles :
    Âge : 34
    Localisation : France

    Informations forums :
    Inscription : Octobre 2006
    Messages : 1 327
    Points : 1 452
    Points
    1 452
    Par défaut
    ok merci

    J'ai testé pour voir les réponses à mon post d'avant: si on appelle un autre constructeur dans le constructeur, même si il est de la même classe, ça n'affecte pas l'instance .

    Le seul truc que j'ai à faire c'est de vider au maximum les constructeurs et de créer des fonction init() qui affecteront le bonnes instances, ou de changer carrément la structure des constructeurs.

    En tout cas sans vous j'y serais pas arrivé


    edit final:

    En fait voilà, je ne peux pas expliciter les arguments dans la déclaration: j'utilise une fonction

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    template <class T>
    MF_Base* MF_Boss::creerMF(int nbargs, ...)
    qui peut créer n'importe quel objet dérivé une ou plusieurs fois de type MF_Base, et les arguments changeant, pour que la fonction soit unique j'ai besoin de constructeurs semblables.

    Donc j'aurais toujours des va_list pour les constructeurs, mais au lieu de gérer ça dans les constructeurs j'utiliserais des fonctions membres des classes, ce qui me permettra d'éviter ces d'appels d'office.

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

Discussions similaires

  1. Réponses: 3
    Dernier message: 06/07/2012, 10h03
  2. Réponses: 5
    Dernier message: 30/03/2010, 10h46
  3. [nlinfit] Comment limiter les valeurs des coeficients ?
    Par zazouille_63 dans le forum MATLAB
    Réponses: 1
    Dernier message: 04/09/2009, 16h21
  4. Comment organiser les appels réseau pour transmettre des mouvements fluides ?
    Par khayyam90 dans le forum Développement 2D, 3D et Jeux
    Réponses: 13
    Dernier message: 07/11/2007, 14h18
  5. Réponses: 10
    Dernier message: 26/05/2006, 23h11

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