PDA

Visualizza la versione completa : [C++] classi e polimorfismo


maluz1
29-10-2013, 22:57
salve a tutti!!:)
ho due classi ereditate da una classe madre, con tutte lo stesso costruttore( mettiamo sia vuoto ).
se io volessi creare un vettore di classi( o puntatori a classi ) misto con le due classi figlie, nel senso che in questo vettore posso introdurvi elementi di tipo classe_derivata_1 E classe_derivata_2, come posso implementare un vettore del genere?

mi sono informato sul polimorfismo ( che io conoscevo come late binding dal linguaggio delphi ) e si usa virtual, il problema è: la direttiva VIRTUAL dove la devo collocare?
- nella dichiarazione di classe: VIRTUAL class {} ?
- nella derivazione dalla classe madre: class classe_derivata : VIRTUAL public classe_madre ?

e poi il vettore come lo potrei dichiarare? è sufficiente una spiegazione :)

grazie mille in anticipo!:)

MItaly
30-10-2013, 01:23
virtual si applica ai metodi; di default i metodi in C++ non sono polimorfici, diventano polimorfici solo quelli che marchi come tali (importante: ricordati sempre se hai una classe con metodi polimorfici di dichiarare un distruttore virtuale, altrimenti puoi avere problemi in caso di deallocazione tramite puntatore a classe base);
il polimorfismo per funzionare correttamente necessita di passare sempre per puntatori o reference, per questo motivo il tuo vettore dovrà essere di tipo classe_base* (ad esempio, std::vector<classe_base *>) e gli oggetti probabilmente andranno allocati dinamicamente. In quest'ultimo caso, uno smart pointer (std::auto_ptr in C++98/03 o std::unique_ptr in C+11) ti può risparmiare la fatica di deallocarli a mano dopo.

maluz1
30-10-2013, 07:35
Grazie mille mitaly per la risposta:)
c è solo una cosa che non ho capito: se nella classe madre non ho metodi come faccio a far derivare le classi figlie per mezzo del polimorfismo? grazie ancora:)

MegaAlchimista
31-10-2013, 13:03
class Padre
{
public:
Padre() {}


};


class Figlio1 : public Padre
{
public:
Figlio1() : Padre() {}


void metodo1() const;
};


class Figlio2 : public Padre
{
public :
Figlio2() : Padre() {}


void metodo2() const;
};

MItaly
31-10-2013, 13:36
Grazie mille mitaly per la risposta:)
c è solo una cosa che non ho capito: se nella classe madre non ho metodi come faccio a far derivare le classi figlie per mezzo del polimorfismo? grazie ancora:)
Sei non hai metodi il polimorfismo serve a poco... :stordita: comunque, ti basta dichiarare il distruttore della classe base come virtual.

maluz1
31-10-2013, 14:08
ma non si può dichiarare il costruttore della classe madre come virtual in modo che appena si dichiara il vettore di oggetti_classe_madre, il compilatore sa già che si tratta di un oggetto delle classi figlie?

perchè però non è ammesso farlo?

grazie mille a entrambi per le risposte :)

MegaAlchimista
31-10-2013, 15:56
i figli li devi creare come figli, poi metterli nel vettore, e quando li tiri fuori devi fare un dynamic_Cast.
Se mi fai vedere come sono la tua classe madre e le figlie e mi spieghi in che modo le devi usare posso farti un esempio

MItaly
31-10-2013, 16:14
ma non si può dichiarare il costruttore della classe madre come virtual in modo che appena si dichiara il vettore di oggetti_classe_madre, il compilatore sa già che si tratta di un oggetto delle classi figlie?
... mi sa che hai molta confusione rispetto a cosa faccia virtual... :stordita:

Un costruttore virtual non ha senso, quando costruisci l'oggetto sai per forza già a compile-time di che tipo è... :stordita: poi se vuoi creare un vettore di soli classi figlie nessuno te lo impedisce, ma ovviamente a quel punto ci puoi memorizzare solo quelle. Se però vuoi memorizzare oggetti di vario tipo (della stessa gerarchia di classi), devi necessariamente usare un vettore di puntatori alla classe base, essenzialmente per un motivo molto semplice: un vettore di oggetti (e non di puntatori) presuppone che tutti gli oggetti abbiano le stesse dimensioni, cosa che in generale è garantita solo per oggetti dello stesso tipo, per cui, per poter riferirsi ad oggetti di tipo diverso, si deve necessariamente passare per i puntatori.

In generale comunque il "tipo vero" di un oggetto al momento di utilizzarlo non ti deve importare, e per questo dynamic_cast, typeid e compagnia dovrebbero essere usati il meno possibile; normalmente quando si progetta una gerarchia di classi si fa in modo che si possa agire sugli oggetti in maniera generica tramite metodi virtuali definiti nella classe base, e poi reimplementati nelle classi figlie in maniera adeguata. A questo punto di rado diventa necessario fare un cast del puntatore alla classe base al "tipo vero" dell'oggetto, visto che si lavora direttamente invocando le funzioni virtuali.

maluz1
01-11-2013, 12:04
effettivamente è la prima volta che tratto il polimorfismo quindi sono abbastanza disorientato.
quindi per creare un vettore di oggetti, devo creare un vettore di puntatori a oggetti( cosa che io avevo già intenzione di fare );
il problema sta però dopo: per ottenere un vettore di DIVERSE classi figlie, come le inserisco nel vettore se in questo ho solo puntatori a classe madre( come mi hai detto te ) ?

mettiamo per esempio che io abbia una classe madre con una sola variabile: int a;

ho poi due classi figlie in cui:
-nella prima ho una seconda variabile : int b;
-anche nella seconda classe figlia ho una seconda variabile: int c;

il vettore che devo creare deve contenere sia elementi della prima classe figlia che della seconda.

si può fare?

a questo punto me la potete implementare questa "struttura" di classi?

grazie mille per la vostra disponibilità Mitaly e MegAlchimista :love:

MItaly
01-11-2013, 14:41
effettivamente è la prima volta che tratto il polimorfismo quindi sono abbastanza disorientato.
quindi per creare un vettore di oggetti, devo creare un vettore di puntatori a oggetti( cosa che io avevo già intenzione di fare );
il problema sta però dopo: per ottenere un vettore di DIVERSE classi figlie, come le inserisco nel vettore se in questo ho solo puntatori a classe madre( come mi hai detto te ) ?
Un puntatore a classe figlia può essere assegnato ad un puntatore a classe base, dato che classe_figlia è una classe_base (principio di sostituzione di Liskov).


mettiamo per esempio che io abbia una classe madre con una sola variabile: int a;

ho poi due classi figlie in cui:
-nella prima ho una seconda variabile : int b;
-anche nella seconda classe figlia ho una seconda variabile: int c;

il vettore che devo creare deve contenere sia elementi della prima classe figlia che della seconda.

si può fare?
Certo, basta memorizzare i puntatori a classe figlia nel vettore, esattamente come faresti con la classe-genitore.


std::vector<classe_base *> vec;
vec.push_back(new classe_base);
vec.push_back(new classe_figlia);

(ricordandosi poi alla fine di fare tutte le delete del caso)

Loading