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 :

Precision sur les destructeurs virtuels


Sujet :

C++

  1. #1
    Membre confirmé Avatar de Linu6
    Profil pro
    Inscrit en
    Août 2007
    Messages
    227
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2007
    Messages : 227
    Par défaut Precision sur les destructeurs virtuels
    Bonjour

    J'ai besoin d'une précision sur les destructeurs virtuels

    soit une classe de base abstraite telle que:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    class Base
    {
    .........
    public:
    virtual ~Base()
    ....
    };
    et une deuxième classe dérivée normale telle que

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    class Derive: public Base
    {
    ....
    public:
    ~Derive();
    ...
    };
    ensuite supposons qu'on veuille créer un Derive en faisant:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    Base *b;
    b = new Derive(...);
    Est qu'il est normal que les objets (Base et Derive) crées de cette sorte ne soient pas détruit à la fin de l'exécution?

    .. parce que lors de l'exécution les messages affichés dans les constructeurs s'affiche sur l'écran, mais pas les messages contenus dans les destructeurs..

    voila.

  2. #2
    Rédacteur

    Avatar de Davidbrcz
    Homme Profil pro
    Ing Supaéro - Doctorant ONERA
    Inscrit en
    Juin 2006
    Messages
    2 307
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 33
    Localisation : Suisse

    Informations professionnelles :
    Activité : Ing Supaéro - Doctorant ONERA

    Informations forums :
    Inscription : Juin 2006
    Messages : 2 307
    Par défaut
    Dans ton code, la classe Base n'est pas abstraite. Elle n'a pas de fonction(s) virtuelle(s) pure(s).

    Ensuite:
    Est qu'il est normal que les objets (Base et Derive) crées de cette sorte ne soient pas détruit à la fin de l'exécution?
    bah oui ! Avec new, tu dit au compilateur, "je vais gérer manuellement la mémoire", ce qui implique de détruire la variable avec delete.
    "Never use brute force in fighting an exponential." (Andrei Alexandrescu)

    Mes articles dont Conseils divers sur le C++
    Une très bonne doc sur le C++ (en) Why linux is better (fr)

  3. #3
    Membre confirmé Avatar de Linu6
    Profil pro
    Inscrit en
    Août 2007
    Messages
    227
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2007
    Messages : 227
    Par défaut
    Tiens donc, c'est donc la fonction virtuelle pure qui rend la classe abstraite?

    Mais pourtant je croyais que le destructeur virtuel seul suffisait pour rendre une classe abstraite, dans la mesure où il interdit son instanciation... non?

  4. #4
    Membre émérite
    Inscrit en
    Juillet 2005
    Messages
    512
    Détails du profil
    Informations forums :
    Inscription : Juillet 2005
    Messages : 512
    Par défaut
    Tiens donc, c'est donc la fonction virtuelle pure qui rend la classe abstraite?
    Tout à fait !

  5. #5
    Membre confirmé Avatar de Linu6
    Profil pro
    Inscrit en
    Août 2007
    Messages
    227
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2007
    Messages : 227
    Par défaut
    Mais dans ce cas là alors, c'est quoi l'intérêt des destructeurs virtuel.. si ce n'est pas rendre une classe abstraite?

  6. #6
    Rédacteur

    Avatar de Davidbrcz
    Homme Profil pro
    Ing Supaéro - Doctorant ONERA
    Inscrit en
    Juin 2006
    Messages
    2 307
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 33
    Localisation : Suisse

    Informations professionnelles :
    Activité : Ing Supaéro - Doctorant ONERA

    Informations forums :
    Inscription : Juin 2006
    Messages : 2 307
    Par défaut
    Si ta classe de base doit servir en tant qu'abstraction, le destructeur virtuel est utile car il va permettre d'appeler le bon destructeur lors du delete.
    "Never use brute force in fighting an exponential." (Andrei Alexandrescu)

    Mes articles dont Conseils divers sur le C++
    Une très bonne doc sur le C++ (en) Why linux is better (fr)

  7. #7
    Membre habitué
    Profil pro
    Inscrit en
    Mai 2008
    Messages
    14
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2008
    Messages : 14
    Par défaut
    Si tu rajoutes un delete b à ton code, tu verras que les 2 destructeurs sont appellés.
    Si tu enleves le virtual du destructeur de la classe de base, seul le destructeur de la classe mère sera appelé.

    C'est à celà que sert le virtual. C'est à dire à faire en sorte que le destructeur de la classe fille soit appelé, même dans le cas où ne possède qu'un pointeur de classe mère

  8. #8
    Expert confirmé
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Décembre 2003
    Messages
    3 549
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Essonne (Île de France)

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

    Informations forums :
    Inscription : Décembre 2003
    Messages : 3 549
    Par défaut
    Si tu enleves le virtual du destructeur de la classe de base, seul le destructeur de la classe mère sera appelé.
    Non. C'est un comportement indéfini.

  9. #9
    Membre chevronné

    Inscrit en
    Août 2007
    Messages
    300
    Détails du profil
    Informations forums :
    Inscription : Août 2007
    Messages : 300
    Par défaut
    Le comportement est bien défini, la description de mazipha est correcte.

  10. #10
    Expert confirmé

    Homme Profil pro
    Ingénieur systèmes et réseaux
    Inscrit en
    Février 2007
    Messages
    4 253
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Ingénieur systèmes et réseaux
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Février 2007
    Messages : 4 253
    Billets dans le blog
    3
    Par défaut
    De façon "simplifiée":
    new = malloc() + appel du constructeur
    delete = appel du destructeur + free()

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    Base* b;
    b = new Derivee(); // malloc() + appel du constructeur de Derivee() (qui va commencer par appeler le constructeur de Base()).
    Dans tous les cas... virtuelle ou non... Pour libérer la mémoire il manque donc un "delete"

    Le destructeur est comme n'importe quelle fonction...

    Si le destructeur de base n'est pas virtuel... Appel du destructeur de b = simple appel à ~Base()

    Si le destructeur de 'Base' est virtuel... Appel du destructeur de b = appel à la fonction correspondante de la table virtuelle de b. En l'occurence ~Derivee()... Qui va (à la fin) appeler ~Base()

  11. #11
    Expert confirmé
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Décembre 2003
    Messages
    3 549
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Essonne (Île de France)

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

    Informations forums :
    Inscription : Décembre 2003
    Messages : 3 549
    Par défaut
    Le comportement est bien défini, la description de mazipha est correcte.
    Ce n'est pas ce que dit le standard.
    C'est bel et bien un comportement indéfini, ce qui est clair puisque les opérateurs new/delete peuvent se surcharger pour chaque type.

  12. #12
    Membre chevronné

    Inscrit en
    Août 2007
    Messages
    300
    Détails du profil
    Informations forums :
    Inscription : Août 2007
    Messages : 300
    Par défaut
    Il faudrait alors informer rapidement Bjarne Stroustrup de ce point précis du standard , car il se permet d'écrire "Had Base's destructor not been virtual, Derived's destructor would not have been called" dans sa FAQ technique. C'est en effet logiquement équivalent au "Si tu enleves le virtual du destructeur de la classe de base, seul le destructeur de la classe mère sera appelé." de mazipha.

  13. #13
    Expert confirmé
    Avatar de Luc Hermitte
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2003
    Messages
    5 292
    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 292
    Par défaut
    Pour appuyer les dire de loufoque:
    Citation Envoyé par Standard C++0x, draft n1606, §3.5.5(delete)/3
    In the first alternative (delete object), if the static type of the operand is different from its dynamic type, the static type shall be a base class of the operand’s dynamic type and the static type shall have a virtual destructor or the behavior is undefined. In the second alternative (delete array) if the dynamic type of the object to be deleted differs from its static type, the behavior is undefined.
    Blog|FAQ C++|FAQ fclc++|FAQ Comeau|FAQ C++lite|FAQ BS|Bons livres sur le C++
    Les MP ne sont pas une hotline. Je ne réponds à aucune question technique par le biais de ce média. Et de toutes façons, ma BAL sur dvpz est pleine...

  14. #14
    Expert éminent
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 635
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 53
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 635
    Par défaut
    Salut,

    Il faut déjà bien comprendre ce que signifie le terme "undefined behaviour", que l'on traduit très justement par "comportement indéfini"...

    Il s'agit d'un comportement pour lequel la norme laisse le créateur du compilateur libre de choisir ce qui sera exécuté.

    Concrètement, un tel comportement peut donc strictement tout faire: appeler le destructeur de la classe de base, celui de la classe dérivée ou... formater ton disque dur

    L'expérience montre que de nombreux compilateurs vont gérer l'absence de destructeur virtuel de la même manière, mais ce n'est donc surement pas une raison pour en tirer une règle ferme et définitive

    Ceci étant dit, revenons en au problème des classes abstraites...

    Une classe est dite "abstraite" si elle dispose au minimum d'une méthode virtuelle pure.

    Une méthode virtuelle pure est une méthode virtuelle pour laquelle on a prévenu le compilateur qu'il n'existe pas d'implémentation de la fonction.

    Cela se fait en ajoutant = 0 à la fin de la déclaration (ex virtual void mafonc() = 0; )
    Comme il n'est pas possible pour le compilateur de créer une instance d'objet si toutes les méthodes ne sont pas définies, une classe pour laquelle il restera une méthode non définie ne sera donc pas instanciable.

    Ainsi, on pourrait tout à fait envisager une arborescence d'hértiage proche de
    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
    /* function1 et function2 sont virtuelle pures 
     * la classe AbstractBase est donc une classe abstraite
     */
    class AbstractBase
    {
        public:
            AbstractBase();
            virtual ~AbstractBase();
            virtual void function1() = 0;//virtuelle pure
            virtual void function2() = 0;//virtuelle pure
    };
    /* si la classe AbstractDerivee dispose des informations permettant
     * de fournir un comportement à function1 et qu'elle définit donc ce 
     * comportement mais qu'elle ne définit pas le comportement de 
     * function2, elle reste abstraite
     */
    class AbstractDerivee : public AbstractBase
    {
        public:
            AbstractDerivee();
            virtual ~AbstractDerivee();
            virtual void function1();
             /* function2 est toujours virtuelle pure ici
              */
    };
    /* il est possible de définir un comportement pour toute méthode virtuelle 
     * accessible... y compris les méthodes virtuelles des classe ancêtres
     * Le fait de définir (enfin) un comportement pour function2 fournira la
     * première classe instanciable
     */
    class Derivee : public AbstractDerivee
    {
        public :
            Derivee();
            virtual ~Derivee();
            virtual function2();
            /* rien n'empêche de redéfinir le comportement de function1... mais ce
             * n'est plus obligatoire ;)
             */
    };
    A méditer: La solution la plus simple est toujours la moins compliquée
    Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
    Compiler Gcc sous windows avec MinGW
    Coder efficacement en C++ : dans les bacs le 17 février 2014
    mon tout nouveau blog

  15. #15
    Membre habitué
    Profil pro
    Inscrit en
    Mai 2008
    Messages
    14
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2008
    Messages : 14
    Par défaut
    L'expérience montre que de nombreux compilateurs vont gérer l'absence de destructeur virtuel de la même manière, mais ce n'est donc surement pas une raison pour en tirer une règle ferme et définitive
    En théorie c'est tout à fait exact, le standard laisse le choix au compilateur, mais en pratique existe t'il un compilateur connu qui ne se comporte pas comme les autres sur ce point?

  16. #16
    Expert confirmé
    Avatar de Luc Hermitte
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2003
    Messages
    5 292
    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 292
    Par défaut
    Une destruction ne se résume pas uniquement à un appel au destructeur. Il y a aussi de la mémoire en jeu.
    Blog|FAQ C++|FAQ fclc++|FAQ Comeau|FAQ C++lite|FAQ BS|Bons livres sur le C++
    Les MP ne sont pas une hotline. Je ne réponds à aucune question technique par le biais de ce média. Et de toutes façons, ma BAL sur dvpz est pleine...

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

Discussions similaires

  1. Réponses: 2
    Dernier message: 20/10/2006, 15h07
  2. Precision sur les transformations
    Par jcloupgarou dans le forum Développement 2D, 3D et Jeux
    Réponses: 7
    Dernier message: 12/07/2006, 09h02
  3. Précision sur les ListBox
    Par SebRs dans le forum Windows
    Réponses: 5
    Dernier message: 04/05/2006, 16h38
  4. precision sur les fichiers
    Par ghostdog dans le forum C
    Réponses: 3
    Dernier message: 20/12/2005, 11h23
  5. [VBA-E]Demande de précision sur les menus
    Par geffdenimes dans le forum Macros et VBA Excel
    Réponses: 5
    Dernier message: 25/06/2003, 10h46

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