|
|||||||
|
|
|
![]() |
|
|
Strumenti |
|
|
#1 |
|
Senior Member
Iscritto dal: Mar 2011
Messaggi: 1050
|
[c++] oggetti classe astratta
Sto cercando di capire delle cose.
Ho una classe astratta (classe base) con metodi virtuali puri. Poi ho una seconda classe (classe figlia.. Con metodi NON virtuali puri) che eredita la classe astratta. So che non si possono istanziare oggetti di una classe astratta. Le mie domande sono: 1) posso istanziare un puntatore a un oggetto? 2)posso istanziare un oggetto se definisco tutti i metodi virtuali puri della classe astratta? |
|
|
|
|
|
#2 | |
|
Senior Member
Iscritto dal: Aug 2001
Città: San Francisco, CA, USA
Messaggi: 13827
|
Quote:
Detto questo: 1) Un puntatore e' sempre instanziabile, perche' e' uno dei tipi primitivi. Il poter instanziare puntatori a classi base astratte e' una delle caratteristiche fondamentali su cui si basa l' OOP in C++. 2) Ovviamente si Ciao
__________________
GPU Compiler Engineer |
|
|
|
|
|
|
#3 |
|
Senior Member
Iscritto dal: Dec 2006
Messaggi: 3808
|
puoi usare dei nomi in maiuscolo per le classi e in minuscolo per i metodi/funzioni membri delle classi ?
Comunque come regola generale non puoi instanziare nessun tipo che sia incompleto ma puoi avere un puntatore ad un tipo incompleto . Va da se che se non puoi instanziare un tipo incompleto, dereferenziare un puntatore ad un tipo incompleto non è una operazione permessa e anche se ci provi dovresti ottenere un errore in fase di compilazione . Per quanto riguarda le funzioni/metodi virtual è una questione di design e convenienza relativa all'ereditarietà e a quanto ti conviene riusare il codice di 1 classe in più sottoclassi, è un modo per scrivere meno codice e/o ottenere un certo comportamento dai tipi . Il punto è semplice, se non definisci tutte le funzioni che sono marcate come pure virtual nel tipo X non puoi istanziare quel tipo, e quel tipo ti serve solo come base dalla quale partire per costruire tutte le sotto-classi del tipo X, ovvero classi che ereditano da X . Questo è qualcosa di molto simile rispetto a quanto accade in C con tipi struct incompleti, in C++ una classe astratta ( nota che in C++ non esistono classi astratte in sé per sé, come qualcosa di definito da una keyword, "classe astratta" è più un retaggio proveniente da Java, in C++ esistono tipi incompleti e metodi virtual/pure virtual, comunque tutti i programmatori C++ sanno cos'è una "classe astratta" in C++ ), alla fine si tratta sempre di tipi incompleti, per completare un tipo ti servono sempre 2 componenti ben definite: la parte relativa alle variabili di istanza e la parte relativa ai metodi/funzioni, i membri del tuo tipo, se queste 2 parti sono ben definite secondo il linguaggio il tuo compilatore saprà cosa farci, altrimenti puoi al massimo creare puntatori e/o riferimenti e il tuo tipo non avrà più valore di una semplice tag, di un semplice nome . |
|
|
|
|
|
#4 | |
|
Senior Member
Iscritto dal: Dec 2006
Messaggi: 3808
|
Quote:
la ragione per la quale si può instanziare un puntatore ad un tipo incompleto è che anche non disponendo della definizione del tipo, e quindi non sapendo il "layout" e la dimensione del tipo, la dimensione di un puntatore è definita dall'ambiente che usi, ergo è possibile costruire ed instanziare una variabile che sia espressione relativa a T*; dereferenziare quello a cui punta T* sarà un altro paio di maniche, ma intanto il puntatore T* lo puoi creare semplicemente perché non ti serve praticamente nessuna informazione su T per creare T* . tu adesso potresti scrivere il codice che ti pare, quanti tipi incompleti ti pare e piace, ma se sei sotto un ambiente a 32 bit, con tutta probabilità il tuo T* t; sarà definibile come una variabile da 32 bit / 4 byte ( 1 byte = 8 bit ) o se sei sotto un ambiente 64 bit t sarà una variabile da ben 8 byte . |
|
|
|
|
|
|
#5 | |
|
Senior Member
Iscritto dal: Jan 2012
Messaggi: 1267
|
Quote:
|
|
|
|
|
|
|
#6 | |
|
Senior Member
Iscritto dal: Dec 2006
Messaggi: 3808
|
Quote:
|
|
|
|
|
|
|
#7 | |
|
Senior Member
Iscritto dal: Mar 2011
Messaggi: 1050
|
Quote:
E se li definisco tutti i metodi virtuali puri della classe base all'interno della classe derivata.. Anche la classe base diventa una classe concreta o rimane astratta e quindi non istanziabile? |
|
|
|
|
|
|
#8 |
|
Senior Member
Iscritto dal: Aug 2001
Città: San Francisco, CA, USA
Messaggi: 13827
|
La definizione della classe base e' del tutto indipendente dalla definizione delle classi derivate. La classe base rimane e rimarrà sempre astratta a meno che non la cambi tu direttamente dandogli delle implementazioni di default.
__________________
GPU Compiler Engineer |
|
|
|
|
|
#9 |
|
Senior Member
Iscritto dal: Mar 2011
Messaggi: 1050
|
E quindi non posso istanziare oggetti della classe base pur definendo tutti i metodi virtuali puri della classe base all'interno della classe derivata?
|
|
|
|
|
|
#10 |
|
Senior Member
Iscritto dal: Dec 2006
Messaggi: 3808
|
Yes, l'ereditarietà di una classe astratta serve solo a te in qualità di programmatore, per quanto riguarda il linguaggio si tratta di un tipo incompleto .
|
|
|
|
|
|
#11 |
|
Senior Member
Iscritto dal: Mar 2011
Messaggi: 1050
|
Nemmeno un puntatore alla classe base?
|
|
|
|
|
|
#12 |
|
Senior Member
Iscritto dal: Aug 2001
Città: San Francisco, CA, USA
Messaggi: 13827
|
Il puntatore di una classe puo' essere sempre creato e usato , anche per riferirsi alle classi derivate.
Per esempio se hai : Codice:
class A { // Classe astratta };
class B : public A { // Classe NON astratta };
Codice:
A *ptr = new B(); ptr->metodo(); // Metodo deve essere definito in A (pure virtual o no) Codice:
A *ptr = new A(); A obj; La classe "A" serve solo per definire una interfaccia da usare poi istanziando una qualche classe derivata. Ti consiglio di prenderti un libro e di leggerti/rileggerti il capitolo su ereditarieta' e polimorfismo, perche' sembra che tu non abbia capito a cosa serve l'esistenza delle classi astratte Vedrai che dopo tutto prendera' immediatamente senso. Ciao
__________________
GPU Compiler Engineer |
|
|
|
|
|
#13 |
|
Senior Member
Iscritto dal: Mar 2011
Messaggi: 1050
|
E posso fare questo?:
list<A> E questo? list<A *> |
|
|
|
|
|
#14 |
|
Senior Member
Iscritto dal: Jan 2012
Messaggi: 1267
|
|
|
|
|
|
|
#15 |
|
Senior Member
Iscritto dal: Mar 2011
Messaggi: 1050
|
[c++] oggetti classe astratta
L'istanziazione qui invece è corretta?? Parlo dell'oggetto "Rifiuto"
Codice:
class GestoreOrdineRifiuti : protected list
{
public:
GestoreOrdineRifiuti();
Rifiuto* pop();
unsigned size() const;
void push (Rifiuto* r)
{
list::iterator it = begin();
while ( it!= end() && *r < *(*it) )
it++;
insert (it, r );
}
};
void SistemaSmaltimento::smaltisciTutti( const GestoreOrdineRiifuti& gestore)
{
while (gestore.size() > 0 )
{
Rifiuto* r = gestore.pop();
r->smaltisci(this);
delete (r);
}
}
Svolgimento
progettare utilizzando l’ereditarietà e il polimorfismo, le interfacce ( solo file di intestazione ) della classe Rifiuto e di almeno due classi che modellano particolari riifuti
enum Tipo { Organico = 0 , Allumino, Plastica };
class Rifiuto
{
public:
Rifiuto ( Tipo, string, string );
virtual ~Rifiuto( );
virtual string getProvenienza( ) const = 0;
virtual string getDestinazione ( ) const = 0;
virtual Tipo getTipo( ) const = 0;
virtual void smaltisci(SistemaSmaltimento* ) const = 0;
protected:
Tipo tipo;
string provenienza;
string destinazione;
};
class Organico : public Rifiuto
{
protected:
int quantità;
string data;
public:
Organico( );
~Organico( );
void setQuantita( int );
void setData ( string );
virtual string getProvenienza( ) const { return provenienza };
virtual string getDestinazione ( ) const { return destinazione };
virtual Tipo getTipo ( ) const { return tipo };
virtual void smaltisci ( SistemaSmaltimento*);
};
//la classe Allmumino sarà uguale
implementare tutti i metodi lasciati incompleti nella classe GestoreOrdineRifiuti
//costruttore GestoreOrdineRifiuti( ), di default perché non ci sono campi da settare
GestoreOrdineRifiuti::GestoreOrdineRifiuti( ) {}
//funzione pop( )
Rifiuto* GestoreOrdineRifiuti::pop( )
{
Rifiuto rifiuto = back( );
pop_back( );
return rifiuto;
}
//funzione size( )
unsigned GestoreOrdineRifiuti::size( )
{
return list.size( );
}
|
|
|
|
|
|
#16 |
|
Senior Member
Iscritto dal: Mar 2011
Messaggi: 1050
|
Up
|
|
|
|
|
|
#17 |
|
Senior Member
Iscritto dal: Oct 2005
Messaggi: 3306
|
Se non sbaglio il tuo codice non istanzia mai un oggetto di un tipo derivato da Rifiuto, quindi è difficile risponderti
Il codice ha un po' di problemi: dichiari che GestoreOrdineRifiuti estende list ma nel metodo size restituisci list.size(), il compilatore dovrebbe darti errore, chi è list? Al metodo pop gli manca un puntatore. Da questo metodo mi pare di capire che list non sia std::list, ma una tua implementazione giusto? Altrimenti dovresti rivedere il design in quanto è male derivare dai container standard non avendo questi il distruttore virtuale. Nota di colore: Codice:
r->smaltisci(this); |
|
|
|
|
| Strumenti | |
|
|
Tutti gli orari sono GMT +1. Ora sono le: 14:48.




















