Newsgroup: it.comp.lang.c++
Titolo: problemi di copia con classi derivate

    Caro NG
    Chiedo una mano su un problema che mi capita da quando, timidamente, ho
cominciato a impiegare la derivazione; per spiegare il mio problema, riporto
qui sotto la struttura generale che ho adottato nella scrittura di classi.
Pur sembrandomi abbastanza elegante e sicuro (le operazioni fondamentali
sono localizzate e questo è importantissimo), ho problemi con la copia di
classi derivate in quanto se derivo ad esempio una classe da 'Cdatbase'
scrivendola alla stessa maniera, le funzioni del tipo 'loc_memcpy" vengono
mascherate. Vengono quindi copiati solo i dati dell'ultima classe derivata
mentre quelli delle genitrici no.
    La domanda è: esiste un modo per risolvere il problema, possibilmente
senza rinunciare a questa o altra struttura che localizzi le operazioni
fondamentali del tipo "loc_"? La cosa più ovvia sembrerebbe richiamare la
funzione mascherata "genitrice::loc_memcpy" nella "loc_memcpy" della classe
derivata. E'
giusto? Come si può massimizzare l'efficienza? Possibili inconvenienti?
    Grazie infinite a chi mi risponderà!!! ;-)
    Corrado
Acor...@alt.itO@
alt.it
[rimuovere le maiuscole per rispondere;
please, remove capitals for answer]
ICQ#25934110
// ................................................... classe generica
class   Cdatbase
{
  private :
    // funzioni
    void      loc_delmem () ;
    void      loc_getmem () ;
    void      loc_memcpy (Cdatbase*, const Cdatbase*) ;
  public :
    // costruttori e distruttori
                Cdatbase (const Cdatbase&) ;
                Cdatbase &operator = (const Cdatbase&) ;
                ~Cdatbase () ;
    // interfaccia
} ;
// .......................... costruttore di copia
Cdatbase::Cdatbase (const Cdatbase &from)
{
  loc_getmem () ;
  loc_memcpy (this,&from) ;
}
// ................... costruttore di assegnazione
Cdatbase &Cdatbase::operator = (const Cdatbase &from)
{
  if(  this != &from  )
  {
    loc_delmem () ;
    loc_getmem () ;
    loc_memcpy (this,&from) ;
  }
  return (*this) ;
}
// .................................. distruttore
Cdatbase::~Cdatbase ()
{
  loc_delmem () ;
}

 mentre quelli delle genitrici no.
Non ho capito bene cosa vuoi ottenere:
1. Una serie di funzioni private ad uso della sola classe base (metodi
private).
2. Una serie di funzioni comuni a tutte le classi derivate (metodi
protected o public).
3. Un'interfaccia comune, ma con funzionalità diverse, a tutte le classe
derivate (metodi virtuali).
4. Una serie di funzioni localizzate ma utilizzabili indipendentemente
dalle istanze (metodi static).
5. Che altro?
EMG

 derivata. 
Le funzioni private non sono disponibili nelle classi derivate
(anche se non ne e' stata definita nessuna con lo stesso nome),
quindi non si possono richiamare.
Di solito il copy constructor di una classe derivata chiama il
copy constructor della classe base nell'initializer list:
Derived::Derived( const Derived & d )
  : Base( d )  // copia della parte vecchia
{
  ... // copia della parte nuova
}
stessa cosa per l'assegnamento:
Derived &
Derived::operator = ( const Derived & d )
{
  Base::operator=( d ); 
  // copia della parte nuova
  return *this;
}
Volendo raccogliere le parti comuni in funzioni di supporto,
si possono definire, per esempio:
class Pippo {
private:
  void destroy();  // deallocazioni varie, ...
  void copyFrom( const Pippo & );  // copia da un altro oggetto
public:
  Pippo::Pippo( const Pippo & pippo ) { // copy constructor
    copyFrom( pippo );
  }
  Pippo::~Pippo() {  // distruttore
    destroy();
  }
  Pippo &
  Pippo::operator= ( const Pippo & pippo ) {  // assegnamento
    if (this != &pippo) {
      destroy();
      copyFrom( pippo );
    }
    return *this;
  }
Non e' il caso di separare l'allocazione della memoria dalla 
copia/inizializzazione. Nel caso dei membri "diretti" della
classe la gestione della memoria e' automatica e non c'e' bisogno
di allocare/deallocare niente. Nel caso di puntatori, normalmente
l'allocazione e l'inizializzazione avvengono in un'unica operazione:
x = new Tipo( ... );
	Mauro

    Chiedo venia...
    Comprendo che chi ha la gentilezza di dare una mano al prossimo dovrebbe
trovarsi con domande ben formulate. Nel caso specifico, il mio problema č
che man mano che derivo classi a cascata *aggiungendo* man mano variabili,
vorrei che le operazioni di copia di *tutte* le medesime fossero eseguite
correttamente e senza ridondanze.
    In altre parole, a ogni nuova derivazione dovrei ogni volta riscrivere
le funzioni di copia "espandendo" quelle precedenti e ripetendo codice. Per
esempio:
class Padre
{
    protected:
    int   a ;
}
class Figlio : public Padre
{
    int   b ;
}
Per Padre, devo copiare solo "a", ma se scrivo il costruttore di copia per
Figlio, devo copiare "b" e *ripetere* la copia di "a". La cosa mi sembra
soggetta ad errori anche se č coerente con il concetto di classe. La domanda
č: posso evitare la copia di "a" in Figlio con qualche meccanismo
"automatico"?
    Sono stato meno confuso? Spero di sě, e di nuovo ringrazio per
l'attenzione.
    Ciao a tutti
    Corrado

 "automatico"?
Non so se ho capito bene, ma non mi sembra ci sia bisogno di tutto
questo. Guarda questo esempio:
#include <iostream>
class A
{
    public:
        int a;
};
class B: public A
{
    public:
        int b;
};
int main()
{
    B b;
    b.a = 123;
    b.b = 321;
    B c = b;
    cout << c.a << " - " << c.b << endl;
    return 0;
}
Come vedi dal risultato che si ottiene (123 - 321), in c sono stati
copiati sia il membro b.b che il b.a senza bisogno di definire alcun
costruttore di copia.
Se non ho capito bene il tuo problema allora rispiegamelo.
EMG


Adesso sei stato sicuramente molto chiaro. Spero di esserlo stato anch'io.
Saluti,
Paolo
----------------------------------------------------------
  Paolo Marotta
  Computer Science, University of Pisa
  home:   
http://www.cli.di.unipi.it/~marotta
----------------------------------------------------------

