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

Langage C++ Discussion :

Appel d'une fonction virtuelle pure depuis un destructeurs


Sujet :

Langage C++

  1. #1
    Membre actif
    Profil pro
    Inscrit en
    Mars 2007
    Messages
    91
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2007
    Messages : 91
    Par défaut Appel d'une fonction virtuelle pure depuis un destructeurs
    J'ai un petit problème de POO avec C++.

    Voilà le souci :
    -j'ai une classe mère abstraite qui défini son destructeur et une méthode abstraite
    -et une classe fille qui redéfini la méthode virtuelle pure

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    class Mother {
    ~Mother();
    virtual string getName() = 0;
    }
     
    Mother::~Mother(){
    cout << "deleting "  << this-getName() << endl;
    }
     
    class Daughter : public Mother {
    virtual string getName(){"the daughter";};
    }
    L'idée serait que la mère puisse appeler la méthode getname de la fille à sa destruction afin d'afficher "deleting the daughter"
    Evidemment ca marche pas, le compilateur râle.

    La solution pourrait être d'utiliser une variable protected "string name" mais je ne préfererais pas. Y aurais-t-il une solution alternative ?

    Merci.

  2. #2
    Membre confirmé Avatar de Furr
    Profil pro
    Développeur informatique
    Inscrit en
    Avril 2009
    Messages
    153
    Détails du profil
    Informations personnelles :
    Âge : 36
    Localisation : France, Nord (Nord Pas de Calais)

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

    Informations forums :
    Inscription : Avril 2009
    Messages : 153
    Par défaut
    Il te faut peut être ajouter un return pour que ça marche, sinon évidemment ton compilateur ne sait pas ce qu'il doit faire avec la string que tu lui mets entre accolades

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    virtual string getName(){return "the daughter";}

  3. #3
    Invité
    Invité(e)
    Par défaut
    Bonjour,
    J'utilise ce type de mécanisme pour des triangles. Un triangle a 3 voisins qui sont aussi des triangles
    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
     
    class TRIANGLE
    {
      TRIANGLE *T1;
      TRIANGLE *T2;
      TRIANGLE *T3;
      TRIANGLE(...);// constructeur
      ~TRIANGLE()
      {
        delete T1;
        delete T2; 
        delete T3;
    // ici une impression que l'on veut; 
      }
    };
    l'avais oublié les étoiles pardon
    Efficacité et sécurité garantie.
    Dernière modification par Invité ; 07/06/2010 à 15h44.

  4. #4
    Rédacteur/Modérateur
    Avatar de JolyLoic
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2004
    Messages
    5 463
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 50
    Localisation : France, Yvelines (Île de France)

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

    Informations forums :
    Inscription : Août 2004
    Messages : 5 463
    Par défaut
    Citation Envoyé par Pierre Dolez Voir le message
    Bonjour,
    J'utilise ce type de mécanisme pour des triangles. Un triangle a 3 voisins qui sont aussi des triangles
    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
     
    class TRIANGLE
    {
      TRIANGLE T1;
      TRIANGLE T2;
      TRIANGLE T3;
      TRIANGLE(...);// constructeur
      ~TRIANGLE()
      {
        delete T1;
        delete T2; 
        delete T3;
    // ici une impression que l'on veut; 
      }
    };
    Efficacité et sécurité garantie.
    Bug garanti surtout
    Si T1 n'est pas un pointeur, pas possible de faire delete dessus. Et d'ailleurs pas besoin de le faire non plus...
    Ma session aux Microsoft TechDays 2013 : Développer en natif avec C++11.
    Celle des Microsoft TechDays 2014 : Bonnes pratiques pour apprivoiser le C++11 avec Visual C++
    Et celle des Microsoft TechDays 2015 : Visual C++ 2015 : voyage à la découverte d'un nouveau monde
    Je donne des formations au C++ en entreprise, n'hésitez pas à me contacter.

  5. #5
    Membre expérimenté
    Profil pro
    Inscrit en
    Mars 2010
    Messages
    188
    Détails du profil
    Informations personnelles :
    Âge : 38
    Localisation : France

    Informations forums :
    Inscription : Mars 2010
    Messages : 188
    Par défaut
    On ne peut appeller des donction virtuelle pur dans la classe mère (cf la FAQ)

    en effet quand tu arrive dans le destructeur de Mother tu as déjà détruit les données de Daughter donc imagine que ta fonction virtuelle pure accède à des données qui appartenaient à Daughter , et bien sa fait boom car on vient de les détruire.

    EDIT : met ton destructeur en virtuel

  6. #6
    Membre actif
    Profil pro
    Inscrit en
    Mars 2007
    Messages
    91
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2007
    Messages : 91
    Par défaut
    Citation Envoyé par Furr Voir le message
    Il te faut peut être ajouter un return pour que ça marche, sinon évidemment ton compilateur ne sait pas ce qu'il doit faire avec la string que tu lui mets entre accolades

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    virtual string getName(){return "the daughter";}

    merci, mais c'est pas vraiment mon problème, j'ai oublié le return parce que j'ai écris directement mon code dans le post. Tu aurais pu aussi noter que je n'avais pas inclus string et iostream

    Bonjour,
    J'utilise ce type de mécanisme pour des triangles. Un triangle a 3 voisins qui sont aussi des triangles
    Code :


    class TRIANGLE
    {
    TRIANGLE T1;
    TRIANGLE T2;
    TRIANGLE T3;
    TRIANGLE(...);// constructeur
    ~TRIANGLE()
    {
    delete T1;
    delete T2;
    delete T3;
    // ici une impression que l'on veut;
    }
    };


    Efficacité et sécurité garantie.
    Merci, mais je ne vois pas vraiment le rapport, j'ai loupé qqch ?


    On ne peut appeller des donction virtuelle pur dans la classe mère (cf la FAQ)

    en effet quand tu arrive dans le destructeur de Mother tu as déjà détruit les données de Daughter donc imagine que ta fonction virtuelle pure accède à des données qui appartenaient à Daughter , et bien sa fait boom car on vient de les détruire.
    EDIT : met ton destructeur en virtuel
    Ok merci, donc du coup pas vraiment d'autre méthode que de définir un membre name ?

  7. #7
    Rédacteur/Modérateur
    Avatar de JolyLoic
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2004
    Messages
    5 463
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 50
    Localisation : France, Yvelines (Île de France)

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

    Informations forums :
    Inscription : Août 2004
    Messages : 5 463
    Par défaut
    Tu peux faire des choses à partir du CRTP.
    Ma session aux Microsoft TechDays 2013 : Développer en natif avec C++11.
    Celle des Microsoft TechDays 2014 : Bonnes pratiques pour apprivoiser le C++11 avec Visual C++
    Et celle des Microsoft TechDays 2015 : Visual C++ 2015 : voyage à la découverte d'un nouveau monde
    Je donne des formations au C++ en entreprise, n'hésitez pas à me contacter.

  8. #8
    Membre expérimenté
    Profil pro
    Inscrit en
    Mars 2010
    Messages
    188
    Détails du profil
    Informations personnelles :
    Âge : 38
    Localisation : France

    Informations forums :
    Inscription : Mars 2010
    Messages : 188
    Par défaut
    Citation Envoyé par agrosjea Voir le message
    Ok merci, donc du coup pas vraiment d'autre méthode que de définir un membre name ?
    Je n'en ai pas d'autre en tête en tout cas .

  9. #9
    Invité
    Invité(e)
    Par défaut
    Désolé, j'ai oublié les étoiles.
    Je les rajoute.

  10. #10
    Expert confirmé

    Inscrit en
    Novembre 2005
    Messages
    5 145
    Détails du profil
    Informations forums :
    Inscription : Novembre 2005
    Messages : 5 145
    Par défaut
    Citation Envoyé par Pierre Dolez Voir le message
    Désolé, j'ai oublié les étoiles.
    Je les rajoute.
    Et il faut gerer les boucles aussi, non?

  11. #11
    Expert confirmé

    Inscrit en
    Novembre 2005
    Messages
    5 145
    Détails du profil
    Informations forums :
    Inscription : Novembre 2005
    Messages : 5 145
    Par défaut
    Citation Envoyé par agrosjea Voir le message
    Ok merci, donc du coup pas vraiment d'autre méthode que de définir un membre name ?
    Decouper ton objet en deux, un qui fournit les services utilises dans les constructeurs/destructeurs ainsi que les membres necessaires a ces services et qui sera detruit par le destructeur de la classe de base, l'autre qui fournit le reste.

    C'est lourd et ca ne se justifie pas toujours.

    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
     
    struct Interface {
       virtual void fnPourConstructeur() = 0;
       virtual void fnPourDestructeur() = 0;
    };
     
    struct Base {
       Base(Interface* ptr) : myPtr(ptr) { ptr->fnPourConstructeur(); }
       ~Base() { myPtr->fnPourDestructeur(); delete myPtr; }
    };
     
    struct Derivee: Base {
       Derivee();
    };
    struct DeriveeHelper: Interface {
       DeriveeHelper() {}
       void fnPourConstructeur() {}
       void fnPourDestructeur() {}
    };
    Derivee::Derivee() : Base(new DeriveeHelper) {}
    DeriveeHelper peut avoir un pointeur sur Derivee, mais pas l'utiliser dans fnPourConstructeur() ni dans fnPourDestructeur().

  12. #12
    Invité
    Invité(e)
    Par défaut
    Bien-sûr.
    Je veux bien donner mon code, mais uniquement en MP ou Mail.
    Mais je veux bien aussi donner tous les détails qu'on voudra.

  13. #13
    Membre expérimenté
    Profil pro
    Inscrit en
    Mars 2010
    Messages
    188
    Détails du profil
    Informations personnelles :
    Âge : 38
    Localisation : France

    Informations forums :
    Inscription : Mars 2010
    Messages : 188
    Par défaut
    Citation Envoyé par Pierre Dolez Voir le message
    Bonjour,
    J'utilise ce type de mécanisme pour des triangles. Un triangle a 3 voisins qui sont aussi des triangles
    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
     
    class TRIANGLE
    {
      TRIANGLE *T1;
      TRIANGLE *T2;
      TRIANGLE *T3;
      TRIANGLE(...);// constructeur
      ~TRIANGLE()
      {
        delete T1;
        delete T2; 
        delete T3;
    // ici une impression que l'on veut; 
      }
    };
    l'avais oublié les étoiles pardon
    Efficacité et sécurité garantie.
    Et T1, T2, T3 ont d'autre voisins aussi qui risquent de les effacer...
    Dans ce cas s'il est utile pour un triangle d'avoir un pointeur vers ses voisins ce n'est absolument pas à lui de les créer ou les supprimer mais à un objet extérieur.

  14. #14
    Invité
    Invité(e)
    Par défaut
    Vous savez, le bout de code que j'ai tapé est le principe général.
    Si vous voulez m'expliquer comment je dois faire, c'est votre problème. Ce n'est pas moi qui ai posé une question. Donc je vous demande de me croire sur parole : la gestion de mes triangles fonctionne très bien, merci.

  15. #15
    Membre actif
    Profil pro
    Inscrit en
    Mars 2007
    Messages
    91
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2007
    Messages : 91
    Par défaut
    Citation:
    Envoyé par agrosjea Voir le message
    Ok merci, donc du coup pas vraiment d'autre méthode que de définir un membre name ?
    Decouper ton objet en deux, un qui fournit les services utilises dans les constructeurs/destructeurs ainsi que les membres necessaires a ces services et qui sera detruit par le destructeur de la classe de base, l'autre qui fournit le reste.

    C'est lourd et ca ne se justifie pas toujours.

    Code :


    struct Interface {
    virtual void fnPourConstructeur() = 0;
    virtual void fnPourDestructeur() = 0;
    };

    struct Base {
    Base(Interface* ptr) : myPtr(ptr) { ptr->fnPourConstructeur(); }
    ~Base() { myPtr->fnPourDestructeur(); delete myPtr; }
    };

    struct Derivee: Base {
    Derivee();
    };
    struct DeriveeHelper: Interface {
    DeriveeHelper() {}
    void fnPourConstructeur() {}
    void fnPourDestructeur() {}
    };
    Derivee:erivee() : Base(new DeriveeHelper) {}


    DeriveeHelper peut avoir un pointeur sur Derivee, mais pas l'utiliser dans fnPourConstructeur() ni dans fnPourDestructeur().
    Merci, je ne pense pas mettre en place une structure aussi lourde pour le moment. En tout cas c'est toujours bon de connaitre ce genre de méthode.

  16. #16
    Rédacteur
    Avatar de 3DArchi
    Profil pro
    Inscrit en
    Juin 2008
    Messages
    7 634
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2008
    Messages : 7 634
    Par défaut
    De toute façon lorsque le destructeur de la classe mère est appelée, ben, la classe fille a été détruite (son destructeur a été exécutée et ses états membres sont donc invalides). La vpointeur ne pointe plus sur la vtable de la classe fille mais sur celle de la classe mère : ça c'est de la cuisine des compilo, car la seule chose que demande la norme c'est que la fonction exécutée dans un constructeur/destructeur soit celle du niveau du constructeur/destructeur en train d'être exécutée (sauf pour les virtuelles pures dans leur classe abstraite pour lesquelles le comportement est indéterminé). Cf : Les fonctions virtuelles en C++.

    Ceci dit j'aimerais bien avoir plus d'info sur le cas réel. Car en somme tu demande à pouvoir continuer à utiliser un objet déjà détruit (ce qui est dans la classe dérivée). On dirait que tu as besoin d'une information au mauvais endroit : elle est 'en dessous' (classe dérivée) alors qu'elle serait peut être mieux 'à-côté' (hiérarchie // comme proposée par Jean-Marc Bourguet). En fait, intuitivement je me pencherais sur un pb de conception et de classe aux responsabilités ambigües.

Discussions similaires

  1. Réponses: 4
    Dernier message: 11/10/2013, 12h08
  2. Réponses: 28
    Dernier message: 09/12/2011, 11h00
  3. Réponses: 2
    Dernier message: 02/10/2008, 16h37
  4. Fonction appelant une fonction virtuelle pure
    Par oodini dans le forum C++
    Réponses: 12
    Dernier message: 19/09/2008, 08h24
  5. Réponses: 2
    Dernier message: 05/03/2006, 19h29

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