Newsgroup: it.comp.lang.c++
Titolo: Copia di un oggetto di cui è nota solo la  classe base

Ciao a tutti, vorrei porre una domanda:
ho una classe base astratta, e una funzione che deve prendere un oggetto 
di una sottoclasse di quesa, e copiarselo.
Ho provato cosě:
class a
{
public:
   virtual int f() = 0;
};
class b
{
private:
   a * a1;
public:
   b(const a & a2)
   {
     a1=new a(a2);
   }
};
Ma naturalmente ho questo errore:
prova.cpp:15: cannot allocate an object of type `a'
prova.cpp:15:   since the following virtual functions are abstract:
prova.cpp:4: 	int a::f()
Come si risolve questo problema?
BTW c'č un'altra cosa che mi incuriosisce: come potrei fare il metodo 
"Clone"? Non mi viene in mente un modo per dare un tipo a questo metodo:
class Cloneable
{
	virtual CHETIPOMETTOQUI clone() = 0;
}
Ciao e grazie per l'attenzione
Vincenzo

 "Clone"? Non mi viene in mente un modo per dare un tipo a questo metodo:
Scusa, ma lo dice la parola stessa, clone() restituisce una copia clonata
dell' oggetto su cui e' invocato.
In c++ il concetto di clonazione e' comunque implementato tramite il
costruttore di copie.
class A {
public:
    A() { }// Costruttore di default
    A(const A& copy) { }// costruttore di copia
    A clone() { return  A(*this); }
};

 };
Così non ha molto senso, però, e non è questo intendeva l'OP.
L'OP si chiedeva qualcos'altro: se ho una classe base (clonable) con
un metodo virtuale puro 'clone', che tipo di ritorno devo specificare?
Il metodo 'clone' di 'clonable' non può che restituire un puntatore a
'clonable'. Grazie alla possibilità della covarianza del tipo di
ritorno, comunque, le classi derivate, che fanno l'override 'clone',
possono (se ce n'è l'esigenza) cambiare il tipo restituito con un
puntatore a un tipo derivato.
  class clonable {
      public:
      virtual clonable* clone() const = 0;
      virtual ~clonable() { } 
  };
  class A: public clonable
  {
        public:
        virtual A* clone() const { return new A(*this); } 
  };
Max

 
[...]
Aggiungerei che clone() e' una funzione membro virtuale un po'
particolare, in quanto deve essere implementata di nuovo in ciascuna
sottoclasse. In questo caso quindi dichiarare una classe base con
funzione membro virtuale pura e' un'indcazione a chi sviluppa le
sottoclassi, ma non un vincolo sufficiente: non c'e' modo di obbligare a
implementare una funzione membro in *tutte* le sottoclassi di una
gerarchia.
Ciao,
Nicola
-- 
Posted via Mailgate.ORG Server - 
http://www.Mailgate.ORG

 puntatore a un tipo derivato.
Si infatti, però mi piacerebbe forzare le classi derivate a dare al 
risultato del metodo clone il loro stesso tipo, diciamo come in eiffel 
con l'operatore "like" (se non ricordo male). Credo di aver capito che 
in C++ non si può fare, mi sbaglio?
Vincenzo

 tipo derivato.
Beh, non voglio istanziare un tipo astratto, solo un puntatore ad un 
tipo astratto, e fai caso che č diverso. Ho una collezione di oggetti, 
tutti derivati da un tipo base (diciamo shape per fare il solito esempio 
da manuale di C++) astratto.
Quando istanzio la collezione, voglio passargli un oggetto con cui 
riempire i suoi elementi, ma di questo oggetto voglio farmi n copie, non 
  n alias!
class Shape
{
public:
  virtual f() = 0;
}
class ShapeContainer
{
private:
  Vector <Shape *> v;
public:
  ShapeContainer(int numel,Shape * defaultValue)
  {
    // Questo costruttore deve fare "numel" copie del valore
    // puntato da "defaultValue
    v = new Vector<Shape*>;
    v.resize(numel);
    for (int i = 0;i<numel; i++)
      v[i] = &(defaultValue.clone());
  }
  // Ci vuole il distruttore che disallochi la memoria
};
Notare il fatto che con il metodo clone() funziona in generale, ma 
rischio che qualcuno lo implementi come non virtuale, e quindi di 
perdere informazione (gravissimo!) nella copia delle sottoclassi che non 
  sono piů state costrette ad implementarlo.
Inoltre qualcuno potrebbe implementare il metodo clone() senza fare una 
copia, ma restituendo semplicemente "this". Ancora peggio!
Ciao e grazie per la risposta
Vincenzo
 

 copia, ma restituendo semplicemente "this". Ancora peggio!
Questo rischio non hai modo di eliminarlo.


 
Se esistesse un metodo clone "di sistema" e non ridefinibile lo 
eliminerei, purtroppo non c'è, e appunto chiedo, non c'è modo di 
scrivere insomma una funzione shape * f(shape *) che restituisce la 
copia esatta del suo parametro, con shape classe astratta? Secondo me un 
modo ci deve essere! Per lo meno, poco portabile, con una malloc, una 
memcpy e un cast si potrà fare (ancora non ho provato). Però non è mica 
detto che tutti gli oggetti abbiano una allocazione contigua, senza 
considerare la differenza fra shallow e deep clone.
Vincenzo

 considerare la differenza fra shallow e deep clone.
Il problema e' che non sai qual'e' il tipo effettivo dell'argomento, e
ne hai bisogno per individuare il costruttore di copia (o suo surrogato)
che ti interessa chiamare.
Quello che puoi fare e' di selezionare a priori esplicitamente di quali
classi consentire la copia e per ciascuna di queste inserire un elemento
in una mappa che ha per chiave l'istanza di std::type_info della classe
e per valore la funzione di copia. Fai piu' lavoro che non utilizzando
l'idiom clone, ma se non altro puoi intercettare i tentativi di
"clonare" istanze di classi non registrate nella tua mappa.


 Nicola
Beh almeno ho capito che quello che volevo non si puň fare :) Grazie 
mille per l'aiuto, credo che alla fine opterň per un appiattimento del 
grafo delle classi che se si puň fare č sempre bene ^__^
Ciao
Vincenzo