Visualizzazione dei risultati da 1 a 9 su 9
  1. #1

    [C++] Distruttore Classe Ereditata

    Salve a tutti, sto facendo dei test ma la situazione non mi è molto chiara.
    Supponiamo di avere
    codice:
    class Base{
    public:
         Base() {v = new double;}
         virtual ~Base() {delete v;}
          void unMetodo() =0;
         //più costruttore di copia, operatore assegnamento, eccetera
    protected:
         doulbe* v;
    }
    
    class Ereditata: public Base{
    public:
         Ereditata() : Base(){}
         ~Ereditata() {  //non ci scrivo niente }
         double nuovoMetodo(int i) const;
    }
    Da quello che ho capito e che mi risulta effettivamente dai test quando chiamo il distruttore della classe figlia viene chiamato anche quello della classe padre, quindi se per caso io scrivessi
    codice:
    ~Ereditata() {  delete v;}
    lo cancellerei due volte?
    Non riesco a trovare questa informazione espressa in modo esplicito da alcuna parte, la cosa che mi inghippa è il "virtual", in teoria se metto virtual nella classe padre, il distruttore della classe padre non dovrebbe essere invocato giusto? O vengono comunque invocati entrambi?

    Se nella classe figlia non inserisco puntatori fra le proprietà, e tolgo il virtual dal distruttore della classe padre, *v verrà cancellato perchè verrà invocato automaticamente ~Base() ?

  2. #2
    Non è compito della classe figlia, quello di deallocare le risorse gestite/allocate dalla classe padre.
    delete non cancella ma dealloca... in particolare dopo aver deallocato non setta a null il puntatore, pertanto se tu facessi:
    codice:
    int* ptr = new int;
    delete ptr;
    delete ptr;
    Genereresti un runtime error

    http://www.cplusplus.com/reference/s...ator%20delete/

    EDIT Il seguente codice non genera errore (perché delete su puntatore NULL non esegue nessuna operazione):
    codice:
    int* ptr = new int;
    delete ptr;
    ptr = NULL;
    delete ptr;
    Experience is what you get when you don’t get what you want

  3. #3
    scusa ho sbagliato termine.
    Quindi mi confermi che anche se è protected, quindi la classe figlia può accedervi, se il decostruttore della classe figlia è vuoto, viene automaticamente chiamato anche il decostruttore della classe padre ed il puntatore viene deallocato?
    Ma in teoria, se io definisco il metodo virtual, quello di Base non dovrebbe essere chiamato.

    Cioè se io ho:
    codice:
    class Base{
    public:
         Base() {v = new double;}
         virtual ~Base() {delete v;}
          virtual int unMetodo() const {return 0;}
    protected:
         doulbe* v;
    }
    
    class Ereditata: public Base{
    public:
         Ereditata() : Base(){}
         ~Ereditata() {}
          int unMetodo() const {return 1;};
    }
    
    int main(...)
    {
    Base* b = new Base();
    Base* e = new Ereditata();
    int x = b->unMetodo();
    int y = e->unMetodo();
    }
    x vale 0 ed y vale 1, cioè il metodo della classe base non viene chiamato, in quanto virtuale. Il distruttore invece fa eccezione e viene chiamato comunque? In questo caso, l'oggetto e dealloca double* v?

  4. #4
    No, assolutamente:
    codice:
    #include <iostream>
    using namespace std;
    
    class Base {
    	public:
    		virtual ~Base() { cout<<"Distruttore di Base\n"; }
    };
    
    
    class Derived : public Base {
    	public:
    		~Derived() { cout<<"Distruttore di Derived\n"; }
    };
    
    int main() {
    	Derived* d = new Derived();
    	delete d;
    	return 0;
    }
    Experience is what you get when you don’t get what you want

  5. #5
    facendo come hai suggerito, chiamando:
    codice:
        Base* v = new Derived();
        delete v;
    mi stampa:
    "distruttore di Derivata"
    "distruttore di Base"

    in pratica li chiama entrambi.
    Idem scrivendo:
    codice:
        Derived* v = new Derived();
        delete v;
    (il distruttore di base è virtual)

    EDIT:

    Mettendo il costruttore non virtuale invece ottengo risultati diversi.
    codice:
        Base* v = new Derived();
        delete v;
    chiama solo il distruttore di Base.
    Questo invece
    codice:
        Derived* v = new Derived();
        delete v;
    li chiama entrambi

  6. #6
    E quale sarebbe il problema?
    Stai programmando ad oggetti e, come ti dicevo poco fa, non è compito della classe derivata quello di deallocare le risorse della classe base.
    Experience is what you get when you don’t get what you want

  7. #7
    ok. Non ho nessun problema infatti volevo solo capire bene.
    Ora sono sicuro di ciò che faccio.
    Grazie degli hint

  8. #8
    Tip: se ti aspetti che da una classe erediterà qualcuno, imposta sempre il distruttore virtuale. In questa maniera verranno automaticamente richiamati prima il distruttore della classe derivata, poi quello della classe base, analogamente a come viene automaticamente richiamato prima il costruttore della classe base, poi quello della classe derivata. Ogni distruttore si occupa della "sua" roba - quello della classe base delle risorse allocate dalla classe base, quello della derivata delle risorse della classe derivata.
    Amaro C++, il gusto pieno dell'undefined behavior.

  9. #9
    Utente di HTML.it L'avatar di shodan
    Registrato dal
    Jun 2001
    Messaggi
    2,381
    This code and information is provided "as is" without warranty of any kind, either expressed
    or implied, including but not limited to the implied warranties of merchantability and/or
    fitness for a particular purpose.

Permessi di invio

  • Non puoi inserire discussioni
  • Non puoi inserire repliche
  • Non puoi inserire allegati
  • Non puoi modificare i tuoi messaggi
  •  
Powered by vBulletin® Version 4.2.1
Copyright © 2024 vBulletin Solutions, Inc. All rights reserved.