Visualizzazione dei risultati da 1 a 9 su 9

Discussione: [C++] Polimorfismo

  1. #1

    [C++] Polimorfismo

    Ciao a tutti.
    Devo creare una classe Struttura che tra i vari metodi ne ha uno addListaProprieta che accetta, come argomento, un'altra classe. Quest'altra classe però è generica e ha delle classi figlie.
    codice:
    class Proprieta
    {
    public:
        Proprieta();
        void setNumero(unsigned int numero);
        unsigned int getNumero();
    
    private:
        unsigned int numero;
    };
    
    class Compressione : public Proprieta
    {
    public:
        Compressione();
        void setTipo(char tipo);
        char getTipo();
    
    private:
        char tipo;
    };
    
    class Struttura
    {
    public:
        Struttura();
        void setVersione(char* versione);
        char* getVersione();
        void addListaProprieta(Proprieta proprieta);
        std::list<Proprieta> getListaProprieta();
    
    private:
        char* versione;
        std::list<Proprieta> lista_proprieta;
    };
    In particolare vorrei, dopo aver creato un'istanza di Struttura, poter aggiungere un'istanza di Compressione tramite addListaProprieta(compressione_1);
    codice:
    void Struttura::addListaProprieta(Proprieta proprieta)
    {
        this->lista_proprieta.push_back(proprieta);
    }
    
    std::list<Proprieta> Struttura::getListaProprieta()
    {
        return this->lista_proprieta;
    }
    Mi è chiaro che deve esserci una relazione, oltre che quella di generalizzazione, tra la classe Proprieta e Compressione. Si utilizzano le classi astratte? Se si come? E nel caso posso comunque definire i metodi di Proprieta che poi saranno ereditati dalla classe Compressione? O li devo per forza definire in Compressione?

    Grazie,
    ciao.

  2. #2
    Utente di HTML.it L'avatar di shodan
    Registrato dal
    Jun 2001
    Messaggi
    2,381
    Innanzi tutto per avere il polimorfismo devi utilizzare un puntatore o un reference. Visto che poi la classe la devi memorizzare in una std::list<>, i reference sono da scartare (non è possibile creare un container di reference).

    Se come hai mostrato, hai bisogno di una lista di Proprieta, tale classe deve mettere a disposizione tutti i metodi che poi saranno utilizzati da Compressione (che però può avere metodi propri non legati a Proprieta). Questo perché in una ottica di polimorfismo, chi utilizzerà il puntatore non sa a quale classe concreta appartiene il metodo (Proprieta? Compressione? Altro?)

    E Proprietà non occorre che sia una classe astratta pura (può fornire metodi di default).
    Alla luce di questo il codice lo puoi modificare in:
    codice:
    class Proprieta
    {
    public:
        Proprieta();
        virtual void setNumero(unsigned int n) { numero = n; }
        virtual unsigned int getNumero() { return numero; }
        virtual void setTipo(char t) { tipo = t; }
        virtual char getTipo() { return tipo; }
    protected:
        unsigned int numero;
        char tipo;
    };
    
    class Compressione : public Proprieta
    {
    public:
        Compressione();
        /* eredita dati e funzioni da Proprieta */
    };
    
    class Struttura
    {
    public:
        Struttura();
        void setVersione(char* versione);
        char* getVersione();
        void addListaProprieta(Proprieta* proprieta);
        std::list<Proprieta*> getListaProprieta();
    
    private:
        char* versione;
        std::list<Proprieta*> lista_proprieta;
    };
    
    void Struttura::addListaProprieta(Proprieta* proprieta)
    {
        this->lista_proprieta.push_back(proprieta);
    }
    
    std::list<Proprieta*> Struttura::getListaProprieta()
    {
        return this->lista_proprieta;
    }
    
    
    in main() {
    
       Struttura strut;
       Proprieta* p1 = new Proprieta;
       strut.addListaProprieta(p1);
       Proprieta* p2 = new Compressione;
       strut.addListaProprieta(p2);
       Proprieta* p3 = new Altro;
       strut.addListaProprieta(p3);
    
    }
    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.

  3. #3
    Tutto chiaro, grazie mille.
    Ciao.

  4. #4
    Volevo chiedere un'altra cosa. Continuando l'esempio di prima, ora vorrei andare a leggere le proprietà presenti nella lista.
    Ho implementato nel main:

    codice:
    Struttura struttura;
    
    Proprieta *compressione = new Compressione(1);
    
    struttura.addListaProprieta(compressione);
    
    std::list<Proprieta*>::iterator i;
    
    for (i = struttura.getListaProprieta().begin(); i != struttura.getListaProprieta().end(); ++i)
    {
        cout <<  ((Compressione*)(*i))->getTipo() ;
    }
    Perché stampa il tipo una volta e poi crasha? Non dovrebbe uscire dal ciclo, visto che è l'unico elemento della lista?
    Grazie.
    Ciao.

  5. #5
    Mai utilizzata la classe list, ma deduco che i nel ciclo è un puntatore, void, quindi puoi fare:

    cout << ((Compressione*)(i))->getTipo() ;

    senza dereferenziare i.

    EDIT: anzi, per usare le potenzialità del polimorfismo,

    cout << ((Proprietà*)(i))->getTipo() ;
    Mi arrestarono un giorno per le donne ed il vino
    Non avevano leggi per punire un blasfemo
    Non mi uccise la morte ma due guardie bigotte
    Mi cercarono l'anima a forza di botte
    Fabrizio De André - Un Blasfemo

  6. #6
    Utente di HTML.it L'avatar di shodan
    Registrato dal
    Jun 2001
    Messaggi
    2,381
    A parte il cast completamente inutile e pericoloso, il problema vero è che stai lavorando su liste diverse, quindi gli iteratori sono diversi.

    codice:
    std::list<Proprieta*> Struttura::getListaProprieta()
    qui restituisci la lista per valore e nel for stai lavorando di fatto su liste diverse.
    Ora hai due possibilità:
    1) restituisci un puntatore/reference alla lista interna (fortemente sconsigliato)
    2) effettui la copia della lista e poi usi quella per ricavare gli iteratori.
    codice:
    Struttura struttura;
    Proprieta *compressione = new Compressione(1);
    struttura.addListaProprieta(compressione);
    std::list<Proprieta*>::iterator i;
    
    std::list<Proprieta*> prop = struttura.getListaProprieta();
    
    for (i = prop.begin(); i != prop.end(); ++i)
    {
        cout << i->getTipo() ;
    }
    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.

  7. #7
    Grazie, ora funziona, ma solo se metto: (*i)->getTipo().
    Inoltre volevo chiederti: se Compressione ha un attributo (con metodi associati set e get) che Proprietà non ha e non conviene fare il casting, metto come virtual i metodi che permettono di accedere all'attributo in Proprietà? E se una proprietà deve ridefinire quel metodo?
    Grazie.
    Ciao.

  8. #8
    Utente di HTML.it L'avatar di shodan
    Registrato dal
    Jun 2001
    Messaggi
    2,381
    Originariamente inviato da ziobacco
    Grazie, ora funziona, ma solo se metto: (*i)->getTipo().
    [/CODE]
    Si, errore mio, scusa.
    [QUOTE}
    Inoltre volevo chiederti: se Compressione ha un attributo (con metodi associati set e get) che Proprietà non ha e non conviene fare il casting, metto come virtual i metodi che permettono di accedere all'attributo in Proprietà? E se una proprietà deve ridefinire quel metodo?
    Grazie.
    Ciao.
    Meglio fare un po' di chiarezza.
    Proprieta espone un'interfaccia di metodi che Compressione eredita ed eventualmente ridefinisce. Quando si invocano tali metodi tramite un puntatore (o reference) non è necessario un cast per farlo: il compilatore richiamerà comunque la funzione corretta. Se tu inserisci in Compressione un metodo proprio, quindi non ereditatato da Proprieta, questo non è richiamabile se non con un cast esplicito. Questo perché Proprieta (di fatto) è un sotto insieme dell'interfaccia di Compressione.
    In questo caso è necessario si un cast, ma occorre fare molta attenzione.
    Se hai una sola relazione di ereditarietà ( Compressione -> Proprieta ), il cast è corretto, ma se ne hai più di una (AltroTipo -> Proprieta) hai un crash. Questo perché Compressione e AltroTipo sono due cose diverse.
    Il C++ mette a disposizione il dynamic_cast<> per operazioni di downcasting. Tu, che hai messo un getTipo(), puoi agire diversamente.
    Supponendo di avere due classi derivate entrambe da Propieta, puoi fare.
    codice:
    std::list<Proprieta*> prop = struttura.getListaProprieta();
    
    for (i = prop.begin(); i != prop.end(); ++i)
    {
        if ((*i)->getTipo() == 'A' ) {
            static_cast<Compressione*>(*i)->metodo_di_compressione( /* params */)
        }
    
        if ((*i)->getTipo() == 'B' ) {
            static_cast<AltroTipo*>(*i)->metodo_di_altro_tipo( /* params */)
        }
    }
    In questo modo avrai la classe corretta sulla quale invocare il metodo personale.
    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.

  9. #9
    Benissimo, è quello che avevo in mente.
    Grazie ancora.

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.