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 :

Destructeurs dérivés et classes


Sujet :

C++

  1. #1
    Débutant  
    Inscrit en
    Novembre 2006
    Messages
    1 073
    Détails du profil
    Informations forums :
    Inscription : Novembre 2006
    Messages : 1 073
    Points : 217
    Points
    217
    Par défaut Destructeurs dérivés et classes
    Bonjour
    j'ai crée les deux classes suivantes, dont l'une dérive de l'autre:

    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
    class vect {
    protected :
    	int nelem; 
    	int *adr;
    public:
    	vect (int);
    	~vect();
    	int & operator[](int);
    };
     
    vect::vect(int n){
       adr=new int[nelem=n];
       int i;
       for(i=0;i<nelem;i++)adr[i]=0;
       }
    vect::~vect(){
       delete adr;
    }
     
    class vectok:public vect{
       private: 
       public:
       vectok(int );
       vectok::~vectok();
       vectok(const vectok &v);
       int taille();
       vectok  operator =(vectok &v);
    };
    le constructeur de la classe vectok est définie comme ceci:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    vectok::vectok(int dim):vect(dim){};
    ensuite, on crée le vecteur vectok comme ceci:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    int main(){
      vectok v(6);
    }
    Ma question est: comment définir le destructeur de vectok en fonction du destructeur de vect?
    Ensuite, comment le définir?
    Par exemple, si je veux détruire le vecteur v, comment dois-je faire?
    Merci

  2. #2
    Expert éminent
    Avatar de Melem
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Janvier 2006
    Messages
    3 656
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 38
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Électronique et micro-électronique

    Informations forums :
    Inscription : Janvier 2006
    Messages : 3 656
    Points : 8 389
    Points
    8 389
    Par défaut
    Alors un peu de cours sur les destructeurs des classes dérivées : Ordre des appels des constructeurs et des destructeurs. N'oublie pas qu'il est également conseillé de toujours déclarer un destructeur "virtual".

  3. #3
    Débutant  
    Inscrit en
    Novembre 2006
    Messages
    1 073
    Détails du profil
    Informations forums :
    Inscription : Novembre 2006
    Messages : 1 073
    Points : 217
    Points
    217
    Par défaut
    Je connais l'ordre d'appel des destructeurs, c'est l'ordre inverse de la déclaration.
    Donc ici, on appel d'abord ~vectok() puis ~vect().
    Ma question, ce serait plutôt:

    Est-ce suffisant de faire:
    Ma deuxième question, c'est:
    pourquoi est-il nécessaire de faire appel au constructeur de la classe de base dans le constructeur de la classe dérivée, alors qu'il n'est pas nécessaire de le faire dans le destructeur.

    merci

  4. #4
    Expert éminent
    Avatar de Melem
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Janvier 2006
    Messages
    3 656
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 38
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Électronique et micro-électronique

    Informations forums :
    Inscription : Janvier 2006
    Messages : 3 656
    Points : 8 389
    Points
    8 389
    Par défaut
    Citation Envoyé par deubelte Voir le message
    Je connais l'ordre d'appel des destructeurs, c'est l'ordre inverse de la déclaration.
    Donc ici, on appel d'abord ~vectok() puis ~vect().
    Ma question, ce serait plutôt:

    Est-ce suffisant de faire:
    Oui, mais c'est comme si tu n'avais pas défini de destructeur car c'est déjà ce que fait le destructeur par défaut.
    Ma deuxième question, c'est:
    pourquoi est-il nécessaire de faire appel au constructeur de la classe de base dans le constructeur de la classe dérivée, alors qu'il n'est pas nécessaire de le faire dans le destructeur.
    C'est pourtant logique, une classe peut avoir plusieurs constructeurs, mais toujours un et un seul destructeur. Dans la classe dérivée, il est nécessaire de spécifier quel constructeur de la classe de base appeler, et avec quels paramètres, avant d'appeler le constructeur de la classe.

  5. #5
    Débutant  
    Inscrit en
    Novembre 2006
    Messages
    1 073
    Détails du profil
    Informations forums :
    Inscription : Novembre 2006
    Messages : 1 073
    Points : 217
    Points
    217
    Par défaut
    Oui, mais c'est comme si tu n'avais pas défini de destructeur car c'est déjà ce que fait le destructeur par défaut.
    ok, l'appel de ~vect(){} sera faire automatiquement quand on fait:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    vectok::~vectok();
    C'est pourtant logique, une classe peut avoir plusieurs constructeurs, mais toujours un et un seul destructeur. Dans la classe dérivée, il est nécessaire de spécifier quel constructeur de la classe de base appeler, et avec quels paramètres, avant d'appeler le constructeur de la classe.
    Donc ce n'est pas nécessaire de faire qqch comme:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    vectok::~vectok():~vect(){};

  6. #6
    Expert éminent
    Avatar de Melem
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Janvier 2006
    Messages
    3 656
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 38
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Électronique et micro-électronique

    Informations forums :
    Inscription : Janvier 2006
    Messages : 3 656
    Points : 8 389
    Points
    8 389
    Par défaut
    Tu as tout mal formulé, mais au moins on peut constater que tu as compris.

  7. #7
    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
    Points : 13 017
    Points
    13 017
    Par défaut
    Salut,
    Citation Envoyé par Melem Voir le message
    N'oublie pas qu'il est également conseillé de toujours déclarer un destructeur "virtual".
    Pour être précis, virtuel s'il est publique et protégé s'il n'est pas virtuel pour un héritage publique. Cf F.A.Q. Pourquoi le destructeur d'une classe de base doit être public et virtuel ou protégé et non virtuel ?

    Citation Envoyé par Melem Voir le message
    Dans la classe dérivée, il est nécessaire de spécifier quel constructeur de la classe de base appeler, et avec quels paramètres, avant d'appeler le constructeur de la classe.
    A noter que si tu ne précises pas quel constructeur appeler, le compilateur appelle quand même le constructeur par défaut des classes de base. Donc, de toute façon, un constructeur sera appelé.

  8. #8
    Débutant  
    Inscrit en
    Novembre 2006
    Messages
    1 073
    Détails du profil
    Informations forums :
    Inscription : Novembre 2006
    Messages : 1 073
    Points : 217
    Points
    217
    Par défaut
    Toujours pour continuer sur les destructeurs, j'ai crée la classe suivante:

    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
    class vecteur3d{
    public:
    	float x,y,z;
    	int *adr;
    public:
    	vecteur3d(float c1=0.0,float c2=0.0,float c3=0.0){
    	     x=c1;y=c2;z=c3;
    		 adr=new int[3];
    		 for(int i=0;i<3;i++) adr[i]=0;
    	};
    	~vecteur3d();
    	vecteur3d(vecteur3d &); 
     
    };
     
    vecteur3d::~vecteur3d(){
    	delete [] adr;
    }
     
    void f(vecteur3d v){
    }
     
    vecteur3d::vecteur3d(vecteur3d &V){
    	this->x=V.x;
    this->y=V.y;
    this->z=V.z;
    int *adr=new int[3];
    for(int i=0;i<3;i++){
        adr[i]=V.adr[i];
    }
    this->adr=adr;
    }
     
    int main(){
    	vecteur3d V(2,3,4);
    	 V.~vecteur3d();}
    Comme vous le voyez, j'ai détruit le vecteur V à la fin. Mais quand on quitte la fonction main, le destructeur est de nouveau appelé, ce qui fait que ça fait planté le code puisque le tableau du vecteur v à déjà été détruit quand j'ai fait mon propre appel de destructeur.

    J'imagine qu'il est dans mon droit de pouvoir détruire des objets quand j'en ai envie/besoin. Donc comment faire pour éviter ce genre de problème?
    Je ne vais pas mettre dans le destructeur un test pour savoir si cela a déjà été détruit.


    Merci

  9. #9
    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 : 39
    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
    J'imagine qu'il est dans mon droit de pouvoir détruire des objets quand j'en ai envie/besoin.
    Et bien non justement, le destructeur est fait pour être appelé automatiquement lorsqu'une instance doit être détruite, tu n'as pas le droit de l'appeler explicitement (sauf cas particulier). Si tu veux une fonction qui fait le ménage dans une classe, prévois une fonctions dédiée, n'utilise pas le destructeur.

  10. #10
    Membre chevronné
    Avatar de Goten
    Profil pro
    Inscrit en
    Juillet 2008
    Messages
    1 580
    Détails du profil
    Informations personnelles :
    Âge : 33
    Localisation : France

    Informations forums :
    Inscription : Juillet 2008
    Messages : 1 580
    Points : 2 205
    Points
    2 205
    Par défaut
    On n'appelle jamais le destructeur explicitement :s. (sauf dans un seul cas mais qui te concerne pas, le placement new).
    Si tu veux gérer toi même la durée de vie alors il te faut l'allouer sur le tas..


    edit : trop tard :p
    "Hardcoded types are to generic code what magic constants are to regular code." --A. Alexandrescu

  11. #11
    Débutant  
    Inscrit en
    Novembre 2006
    Messages
    1 073
    Détails du profil
    Informations forums :
    Inscription : Novembre 2006
    Messages : 1 073
    Points : 217
    Points
    217
    Par défaut
    Et bien non justement, le destructeur est fait pour être appelé automatiquement lorsqu'une instance doit être détruite, tu n'as pas le droit de l'appeler explicitement (sauf cas particulier). Si tu veux une fonction qui fait le ménage dans une classe, prévois une fonctions dédiée, n'utilise pas le destructeur.
    Ca c'est intéressant, je ne le savais pas!
    Alors il faut créer une fonction qui recopie ce que fait le destructeur.
    Comme par exemple:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    void detruit(vecteur3d v){
    	v.x=0;	v.y=0;v.z=0;
    	delete[] v.adr;
     
    }
    j'ai essayé mon programme, et ça plantait. Je viens de reessayer en modifiant le destructeur. J'ai supprimé la ligne de code delete[]..

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    vecteur3d::~vecteur3d(){}
    et ça marche!!



    Si tu veux gérer toi même la durée de vie alors il te faut l'allouer sur le tas..
    En faisant new....

  12. #12
    Expert éminent
    Avatar de Melem
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Janvier 2006
    Messages
    3 656
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 38
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Électronique et micro-électronique

    Informations forums :
    Inscription : Janvier 2006
    Messages : 3 656
    Points : 8 389
    Points
    8 389
    Par défaut
    Citation Envoyé par 3DArchi Voir le message
    A noter que si tu ne précises pas quel constructeur appeler, le compilateur appelle quand même le constructeur par défaut des classes de base. Donc, de toute façon, un constructeur sera appelé.
    Sauf qu'ici aucun constructeur par défaut n'a été défini donc un appel explicite à un constructeur de base est requis dans chaque constructeur de la classe dérivée, pour les raisons que j'ai déjà évoquées. Ou alors on ajoute un constructeur par défaut à la classe de base et dans ce cas tu as parfaitement raison.

  13. #13
    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 : 39
    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
    j'ai essayé mon programme, et ça plantait. Je viens de reessayer en modifiant le destructeur. J'ai supprimé la ligne de code delete[]..
    Ca plantait parce que tu oubliais de mettre le membre adr à NULL après l'avoir détruit. Donc le second delete qui était effectué tombait sur de la mémoire déjà désallouée, et paf.

    Ensuite, pas besoin de dupliquer de code, le constructeur peut très bien appeler lui aussi cette fonction.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    void detruit(vecteur3d v)
    Pourquoi passer un paramètre ? Une telle fonction (pour peu qu'elle ait un intérêt) devrait détruire l'objet courant (this), ça n'a pas de sens de dire à v1 de détruire un autre objet v2. En plus tu passes une copie d'un vecteur3d, donc ça détruisait une copie locale et non l'original.

  14. #14
    Débutant  
    Inscrit en
    Novembre 2006
    Messages
    1 073
    Détails du profil
    Informations forums :
    Inscription : Novembre 2006
    Messages : 1 073
    Points : 217
    Points
    217
    Par défaut
    Pourquoi passer un paramètre ? Une telle fonction (pour peu qu'elle ait un intérêt) devrait détruire l'objet courant (this), ça n'a pas de sens de dire à v1 de détruire un autre objet v2.
    Je n'ai pas déclaré la fonction détruite dans la classe vecteur3d, donc pourquoi prendrait t-elle un argument implicite? Je veux dire qu'on ne peut pas faire

    ayant fait:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    void detruire(vecteur3d v){
    delete [] v.adr;
    }



    (attention: je sais pas si j'ai raison)


    En plus tu passes une copie d'un vecteur3d, donc ça détruisait une copie locale et non l'original.
    Exacte, j'aurais du passer en référence l'argument, et non pas en valeur.

  15. #15
    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 : 39
    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
    Je n'ai pas déclaré la fonction détruite dans la classe vecteur3d, donc pourquoi prendrait t-elle un argument implicite?
    Ah ok, je pensais que tu en avais fait une fonction membre. En général ce genre de fonction est membre, c'est un peu bizarre de la mettre en fonction non-membre.

  16. #16
    gl
    gl est déconnecté
    Rédacteur

    Homme Profil pro
    Inscrit en
    Juin 2002
    Messages
    2 165
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 45
    Localisation : France, Isère (Rhône Alpes)

    Informations forums :
    Inscription : Juin 2002
    Messages : 2 165
    Points : 4 637
    Points
    4 637
    Par défaut
    Juste une petit précision :

    Citation Envoyé par Melem Voir le message
    Sauf qu'ici aucun constructeur par défaut n'a été défini mais un autre constructeur a été défini donc un appel explicite à un constructeur de base est requis dans chaque constructeur de la classe dérivée, pour les raisons que j'ai déjà évoquées. Ou alors on ajoute un constructeur par défaut à la classe de base et dans ce cas tu as parfaitement raison.

  17. #17
    Débutant  
    Inscrit en
    Novembre 2006
    Messages
    1 073
    Détails du profil
    Informations forums :
    Inscription : Novembre 2006
    Messages : 1 073
    Points : 217
    Points
    217
    Par défaut
    est-ce possible qu'une fonction prenne un argument du style: &&u
    comme par exemple:
    int f(int &&u){
    return u=u+1
    }
    D'après ce que j'ai compris, ce n'est pas possible, car il n'existe pas de référence de référence. On a en fait &&u=&.

    Merci

  18. #18
    Membre chevronné
    Avatar de Goten
    Profil pro
    Inscrit en
    Juillet 2008
    Messages
    1 580
    Détails du profil
    Informations personnelles :
    Âge : 33
    Localisation : France

    Informations forums :
    Inscription : Juillet 2008
    Messages : 1 580
    Points : 2 205
    Points
    2 205
    Par défaut
    Avec la prochaine norme, ça existera (c'est une rvalue références). Avec la norme actuelle non c'est pas possible.
    "Hardcoded types are to generic code what magic constants are to regular code." --A. Alexandrescu

  19. #19
    Membre chevronné
    Avatar de Joel F
    Homme Profil pro
    Chercheur en informatique
    Inscrit en
    Septembre 2002
    Messages
    918
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Chercheur en informatique
    Secteur : Service public

    Informations forums :
    Inscription : Septembre 2002
    Messages : 918
    Points : 1 921
    Points
    1 921
    Par défaut
    Citation Envoyé par Goten Voir le message
    Avec la prochaine norme, ça existera (c'est une rvalue références). Avec la norme actuelle non c'est pas possible.
    attention que la notation n'est simialire qu'en apparence, une rvalue n'ets pas une reference de reference

  20. #20
    Débutant  
    Inscrit en
    Novembre 2006
    Messages
    1 073
    Détails du profil
    Informations forums :
    Inscription : Novembre 2006
    Messages : 1 073
    Points : 217
    Points
    217
    Par défaut
    Je continue sur les constructeurs: j'avais crée un programme qui testait la taille de différents objets, et il m'arrivait de créer des objets "vides". Mais cela ne fonctionnait pas, jusqu'à ce que je me rende compte jusqu'a ce que je me rende compte qu'une instance d'une classe vide n'est pas vide. c'est-à-dire qu'elle occupe une place dans la mémoire:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     
    class A{};
     
    int main(){
    	A a;
    cout<<sizeof(a);
    }
    En réalité l'objet a n'a pas 0 octet, mais 1. ce qui semble plutôt étrange.
    N'est-il pas possible de créer des objets de taille 0, voire des variables, des éléments?

+ Répondre à la discussion
Cette discussion est résolue.
Page 1 sur 2 12 DernièreDernière

Discussions similaires

  1. destructeur d'une classe dérivée du type list
    Par Haze. dans le forum Général Python
    Réponses: 2
    Dernier message: 19/11/2007, 01h11
  2. [POO] destructeur d'une classe
    Par mulot49 dans le forum Langage
    Réponses: 1
    Dernier message: 24/10/2007, 17h54
  3. Réponses: 5
    Dernier message: 02/10/2007, 14h04
  4. Destructeur d'une classe.
    Par hitomidoaxbv dans le forum C++
    Réponses: 3
    Dernier message: 29/06/2007, 09h28
  5. Conseil du compilo sur un destructeur d'une classe
    Par okparanoid dans le forum Langage
    Réponses: 2
    Dernier message: 20/07/2005, 20h11

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