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 :

Constructeurs et classe de base virtuelle


Sujet :

C++

  1. #1
    Membre du Club
    Inscrit en
    Juin 2002
    Messages
    37
    Détails du profil
    Informations forums :
    Inscription : Juin 2002
    Messages : 37
    Points : 42
    Points
    42
    Par défaut Constructeurs et classe de base virtuelle
    Bonjour,

    Je dois manipuler un ensemble d'objets. Tous ces objets ont en commun un ensemble d'attributs et d'opérations (disons E1). De plus d'autres ensembles d'attributs et opérations (appelons les F1,...,Fn) sont communs à certains des objets manipulés (mais pas à tous). Enfin, certaines des opérations de F1,...,Fn utilisent les attributs de E1. Pour implémenter ça, je voudrai utiliser des "classes de bases virtuelles". Un petit bout de code pour fixer les idées :

    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
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
     
    #include <iostream>
    using namespace std;
     
    //------------------------------------------------------------------------
    class Commun {
    protected:
        int att_E;
     
    public:
        Commun(int _att_E) : att_E(_att_E) {}
     
        void op_E() {
            cout << att_E << endl;
        }
    };
     
    //------------------------------------------------------------------------
    class Partiel1 : virtual public Commun {
    protected:
        int att_F1;
     
    public:
        Partiel1(int _att_F1) : Commun(0), att_F1(_att_F1) {}
        void op_F1() {
            cout << att_E << " " << att_F1 << endl;
        }
    };
     
    //------------------------------------------------------------------------
    class Partiel2 : virtual public Commun {
    protected:
        int att_F2;
    };
     
    //------------------------------------------------------------------------
    class A : public Partiel1 {
    public:
        A(int _att_E, int _att_F1) : Commun(2*_att_E), Partiel1(_att_F1) {}
    };
     
    //------------------------------------------------------------------------
    class B : public Partiel1, public Partiel2 {
    };
     
    //------------------------------------------------------------------------
    class SubA : public A {
    public:
        SubA(int _att_E, int _att_F1) : Commun(_att_E), A(_att_E, _att_F1) {}
    };
     
    //------------------------------------------------------------------------
    int main(int argc, char* argv[]) {
        A a(123, 456);
        a.op_E();
        a.op_F1();
        // -> Affiche :
        // 246
        // 246 456
     
        SubA sa(314, 271);
        sa.op_E();
        sa.op_F1();
        // -> Affiche :
        // 314
        // 314 271
     
        return 0;
    }
    Voilà donc mes questions :

    1) Pourquoi suis-je obligé d'appeler le constructeur de "Commun" dans la liste d'initialisation de "A" (si je ne le fais pas, ça compile pas et, normalement, on n'a le droit que d'appeler les constructeurs des classes juste au dessus dans la hiérarchie)

    2) En ajoutant quelques messages de debug dans les constructeurs, je me rends compte que le constructeur de "Commun" n'est appelé qu'une seule fois : cela veut-il dire que l'appel de ce constructeur ("Commun(0)") dans la liste d'initialisation de "Partiel1" est ignoré ?

    3) Y'a-t-il un moyen d'éliminer l'espèce de redondance dans la liste d'initialisation de "SubA" : pourquoi devoir transmettre 2 fois _att_E puisque l'initialisation de "Commun" semble être ignorée dans le constructeur de "A" (en effet, sa->opE() affiche 314 et non pas 624) ?

    4) Existe-t-il une autre solution pour implémenter mon problème ? Bref, est-il possible de faire sans héritage virtuel ?

    5) Connaissez-vous une bonne documentation sur les classes virtuelles (les facs, les bouquins et les tutos sont très bavards à propos des méthodes virtuelles, des classes abstraites mais il n'y a jamais grand chose sur les classes virtuelles, y compris dans le Stroustrup !)

    Merci.

  2. #2
    Membre averti
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Mai 2006
    Messages
    366
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : France, Paris (Île de France)

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

    Informations forums :
    Inscription : Mai 2006
    Messages : 366
    Points : 444
    Points
    444
    Par défaut
    1] et 2] Le fait de déclarer Commun comme base virtuelle empêche justement l'appel de son constructeur lors de la construction de Partiel1 ou Partiel2.

    Lors de la construction d'un objet Dérivé, une zone de mémoire va être réservée pour un objet de type "Mère" et le reste pour les données spécifiques de Dérivé. La partie "Mère" va être initialisée par un appel au constructeur de cette classe (par défault et implicite si tu ne le spécifies pas), puis ce sera ensuite la partie "Dérivé".

    Maintenant dans ton schéma, si l'appel au constructeur Commun était autorisé (voire automatique) depuis les classes Partiel1 et Partiel2, alors DEUX objets communs seraient créés lors de la construction de B : 1 pour la partie Partiel1 et un pour la partie Partiel2. C'est pour éviter cela que l'héritage est virtuel et le constructeur pas appelé (potentiellement, il peut très bien y avoir un nombre arbitraire de Partiel, donc c'est à toi d'initialiser la base commune).

    3] Dans tes constructeurs Partiel, enlève carrément les paramètres qui initialisent la classe Commun, puisque de toute façon il te sera impossible de l'appeler depuis ces classes.

    4] La composition est souvent une bonne alternative : tu gardes ta hiérarchie de Commun et partiels, par contre au lieux de dériver de plusieurs partiels tu les encapsules dans ta classe.

    5] Je vois pas trop, perso le Stroupstrup est assez complet je trouve

    EDIT : j'avais lu que tu cherchais ds choses sur l'héritage virtuel. Effectivement comme le dit Eusebe il n'existe pas de classes virtuelles en C++.

  3. #3
    Membre expert
    Avatar de Eusebe
    Inscrit en
    Mars 2006
    Messages
    1 992
    Détails du profil
    Informations personnelles :
    Âge : 47

    Informations forums :
    Inscription : Mars 2006
    Messages : 1 992
    Points : 3 344
    Points
    3 344
    Par défaut
    Tu développe sous quoi (et en quoi ?) ?

    En C++, à ma connaissance, les classes virtuelles n'existent pas.

    Et tu ne peux appeler que le constructeur des classes de base.

    Et quand une classe hérite d'une classe de base qui n'a pas de constructeur par défaut, on est obligé d'appeler explicitement le constructeur de la classe de base (voir les classes B et Partiel2).

    Et quand une classe est susceptible d'être héritée, il faut déclarer son destructeur virtuel...

    Bref, je ne comprend pas bien ce que tu as fait, ni comment tu l'as fait (ou plutôt sous quel compilo) !

  4. #4
    Expert éminent sénior
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 382
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France

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

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 382
    Points : 41 588
    Points
    41 588
    Par défaut
    Citation Envoyé par Eusebe
    En C++, à ma connaissance, les classes virtuelles n'existent pas.
    Il est ici question de classes de base virtuelles, un moyen utilisé par le C++ pour résoudre les problèmes d'héritage multiple en losange.

  5. #5
    Membre expert
    Avatar de Eusebe
    Inscrit en
    Mars 2006
    Messages
    1 992
    Détails du profil
    Informations personnelles :
    Âge : 47

    Informations forums :
    Inscription : Mars 2006
    Messages : 1 992
    Points : 3 344
    Points
    3 344
    Par défaut
    Citation Envoyé par Médinoc
    Il est ici question de classes de base virtuelles, un moyen utilisé par le C++ pour résoudre les problèmes d'héritage multiple en losange.
    Oups, j'avais mal lu...

    Toujours est-il que mon compilateur (GCC, avec C::B) ne compile pas l'exemple donné (ce qui parait assez logique), parce que les classes Partiel2 et B n'appellent pas le constructeur de leurs classes de base...

  6. #6
    Membre du Club
    Inscrit en
    Juin 2002
    Messages
    37
    Détails du profil
    Informations forums :
    Inscription : Juin 2002
    Messages : 37
    Points : 42
    Points
    42
    Par défaut
    Citation Envoyé par Eusebe
    Tu développe sous quoi (et en quoi ?) ?

    En C++, à ma connaissance, les classes virtuelles n'existent pas.

    Et tu ne peux appeler que le constructeur des classes de base.

    Et quand une classe hérite d'une classe de base qui n'a pas de constructeur par défaut, on est obligé d'appeler explicitement le constructeur de la classe de base (voir les classes B et Partiel2).

    Et quand une classe est susceptible d'être héritée, il faut déclarer son destructeur virtuel...

    Bref, je ne comprend pas bien ce que tu as fait, ni comment tu l'as fait (ou plutôt sous quel compilo) !

    Je développe en C++ sous Visual C++ !

    Effectivement, si je déclare un objet de type B, ça ne compile plus. En fait, cet exemple compilait dans la mesure où Partiel2 et B n'étaient jamais utilisé (Visual C++ ne les prenait tout simplement pas en compte). D'ailleurs, si je désactive les optimisations, ça ne compile plus. J'avais juste mis Partiel2 et B à titre d'illustration.

    Pour le terme "classe virtuelle" je ne sais pas si j'utilise le bon mot mais le concept existe. B. Stroustrup parle systématiquement de de "classe de base virtuelle" mais la majorité des autres ouvrages que j'ai consulté raccourcissent et disent "classe virtuelle"... so do I.

    Dans la mesure où l'exemple que j'ai donné est complètement inutile et n'a qu'un but illustratif, je me suis effectivement permi de ne pas traiter le "problème" des destructeurs. D'ailleurs, je ne suis pas sûr qu'en l'état, cet exemple fasse la moindre fuite de mémoire...

  7. #7
    Expert éminent sénior
    Avatar de Luc Hermitte
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2003
    Messages
    5 282
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Août 2003
    Messages : 5 282
    Points : 11 036
    Points
    11 036
    Par défaut
    Une des meilleures ressources que je connaisse sur l'héritage multiple
    -> Multiple Inheritance Considered Useful.

    Sinon, je n'aime pas l'appellation "classe virtuelle". Pour certains cela se traduit par "classe de base virtuelle", pour d'autres par "classe où toutes les fonctions sont virtuelles pures". Bref, cela ne veut rien dire, et en plus c'est tellement ambigü que l'on ne peut pas trouver de convertion implici... hum.

    Bref, j'aime pas. Un peu le même combat que "surdéfinition", tout le monde ne comprend pas la même chose, c'est trop imprécis. Du coup mieux vaut oublier ces termes.

  8. #8
    Membre expérimenté
    Avatar de Patriarch24
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Septembre 2003
    Messages
    1 047
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : France

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

    Informations forums :
    Inscription : Septembre 2003
    Messages : 1 047
    Points : 1 640
    Points
    1 640
    Par défaut
    Moi je traduit
    class Partiel2 : virtual public Commun
    par : héritage virtuel. Commun n'a rien de virtuel... D'ailleurs, il n'existe pas de classes virtuelles à proprement parler (c'est un non-sens... il existe uniquement des fonctions membres virtuelles), mais il existe des classes abstraites (répondant au joli nom d'ABC pour Abstract Base Class) aussi appelées (à mon avis à tort) virtuelles pures (là encore seules les méthodes peuvent être virtuelles pures).

Discussions similaires

  1. Réponses: 4
    Dernier message: 22/10/2011, 20h07
  2. Réponses: 13
    Dernier message: 20/10/2008, 17h36
  3. Réponses: 15
    Dernier message: 05/07/2007, 02h29
  4. [MySQL] proble class pour base de donner
    Par alexmorel dans le forum PHP & Base de données
    Réponses: 2
    Dernier message: 27/10/2005, 16h56
  5. Réponses: 7
    Dernier message: 15/07/2005, 16h07

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