• [^] # Re: Ordre des constructeurs

    Posté par . En réponse au message Le constructeur d'une classe de base peut-il savoir qu'il n'est pas le dernier?. Évalué à 2.

    Personnellement, je m’étais fait avoir sur un destructeur qui appelait une fonction virtuelle pure... ça lance une belle exception ;-).

    Oui oui, c'est logique, je l'ai réalisé dès que j'ai repéré un bug lié à ce problème. Le principe de ma hiérarchie de classe est d'utiliser des méthodes génériques de la classe de base, et tout fonctionnait très bien jusqu'à ce que j'essaye de le faire aussi dans le constructeur.

    Si tu as ce besoin dans le constructeur, c’est que ta hiérarchie est mal répartie. Ce n’est pas un problème de C++, tu aurais le même type d’ennuis dans tous les langages objets que je connais.

    Pour chaque classe tu dois savoir quelles sont ses responsabilités. Avoir les données minimales pour gérer ces responsabilités.

    Si je reprends ton exemple de Polygone, il est logique que le polygone possède la liste des points. C’est même à lui de retourner le nb de points mais en regardant le nombre d’éléments dans la liste.

    int Polygone::get_nb_points() { return v.size(); }

    Par contre positionner les points c’est à la classe fille de le faire... via une nouvelle fonction de Polygone : addPoint.

    Ensuite, je ferais une classe spécifique comme ça :

    template <int n> class PolygoneRegulier: public Polygone 
    {
     PolygoneRegulier():Polygone() {
     // Ici Polygone est construit, donc on peut utiliser ses méthodes.
     for (int i = 0; i < n; i++) {
     Point p = Point(cos(i*360/n), sin(i*360/n));
     addPoint(p);
     }
     }
    }
    typedef PolygoneRegulier<3> Triangle;
    typedef PolygoneRegulier<4> Carre;

    J’ai tapé ça vite fait... je ne sais même pas si ça compile ;-) mais l’idée est là.

    Pour être honnête, j'ai même pensé à passer this en paramètre du constructeur de la classe de base, mais j'ai rapidement décidé que je ne voulais même pas savoir si c'était légal.

    Ce n’est pas nécessaire, le this est le même dans toute la hiérarchie. Juste qu’une méthode parente n’a pas à appeler une méthode d’une fille, car sinon comment choisir ? Ex :

    class Mere
    {
    public:
     Mere() { Fille::methode(); }
    };
    class Fille:public Mere {
     ...
     void methode();
    };
    class Fille2: public Mere {
     ...
     void methode();
    };
    Fille2 var;
    };

    Comment peut-on construire var puisque var sera une Fille2 ainsi qu’une Mere. Mais pas une Fille ! Donc si ça compilait se serait catastrophique.

    Pour la suite je ne suis pas certains d’avoir tous saisi.

    Je suis quand même un peu surpris que le C++ n'ait pas un mécanisme simple pour s'assurer qu'une fonction est exécutée exactement une fois lors de la construction, sans pour autant contraindre la hiérarchie de classes (typiquement, pour réserver de la mémoire).

    Je l’ai expliqué au dessus. Après tu peux faire une construction via une factory.

    Dès que les classes filles appellent le constructeur des classes mères, on se retrouve à devoir choisir où réserver la mémoire ;

    Je ne comprends pas.

    soit dans le constructeur de la classe mère (et donc, de devoir se débrouiller pour passer des variables membres en paramètre du constructeur, ce qui est quand même étrange), soit dans le constructeur de la classe fille (ce qui rend presque mécaniquement la classe mère virtuelle).

    Ton problème vient du fait que tu dois penser en terme de responsabilité :

    • Mon objet c’est quoi ?
    • Quel information caractérise se quoi.
    • Quel comportement je lui donne.

    Si a l’une de ses questions tu dois avoir des méthodes dans des classes qui hériteront c’est qu’il y a un soucis.

    Disons que je comprends le pourquoi du comment techniquement, mais que ça me semble être un mécanisme légitime en POO...

    Je pense que tu découvre la POO et que tu as trouvé génial l’héritage et les fonctions virtuelles, mais il faut bien comprendre se qu’elles permettent et pas leur donner des pouvoirs qu’elles n’ont pas.

    L’exemple classique s’est la figure géométrique que l’on veut déplacer. Il suffit d’appeler la fonction dessiner dans la fonction deplacer. En rendant dessiner virtuelle, ça permet d’avoir une seule implémentation de deplacer.

    Je te conseillerai un livre très bien écrit : Programmer en langage c++ de Claude Delannoy. J’ai une très vieille version 4° édition 1998... il manque le c++03, c++11... néanmoins, la présentation du livre est très didactique et une fois assimilé les concepts de base, les informations glanées sur internet n’ont plus à être aussi didactique.

    Finalement, j’ai fais un paver ! J’espère que ce n’est pas trop indigeste.