L`object slicing Ci domandiamo cosa succede - TelPar

Download Report

Transcript L`object slicing Ci domandiamo cosa succede - TelPar

Appunti di OOP in C++
francesco parisi telpar.altervista.org
L'object slicing
Ci domandiamo cosa succede quando a una funzione passiamo, per valore, un oggetto di una classe
derivata laddove la funzione s'aspetta, invece, un oggetto della classe base.
Innanzitutto, lo scambio è del tutto lecito perché ce lo dice l'ereditarietà pubblica: si può sempre
usare un oggetto di classe derivata laddove se ne aspetta uno di classe base. Es.:
class B { ... };
class D : public B { ... };
void f ( B b );
...
D d;
f( d );
Cosa accade quando viene chiamata la funzione?
Se la classe base non è astratta viene invocato il costruttore di copia della classe base, che creerà
così un oggetto di tale classe. A questo punto accade un qualcosa che può essere indesiderata.
Il compilatore, come detto, accetta la copia di un oggetto di classe derivata su un oggetto di classe
base, ma ne copia solo la parte “base”.
Tutto quanto porta di suo l'oggetto di classe derivata viene “tagliato fuori” (slicing off).
L'oggetto, dunque, perde tutti quegli attributi e comportamenti che caratterizzavano la sua
specificità, la sua specializzazione (ivi compresi metodi virtuali ridefiniti) e viene così “declassato”
a un oggetto di classe base, privo di ogni specializzazione.
Se, invece, la classe base è astratta (cioè contiene almeno una funzione virtuale pura) non avviene la
chiamata del costruttore di copia, semplicemente perché la classe base astratta non ha compiti di
creare oggetti ossia non implementa mai alcun tipo di costruttore (né tantomeno quello di copia).
Se si tenta di creare un oggetto, il compilatore genera un errore che previene lo slicing dell'oggetto.
Quindi, nel caso di classe base astratta non potremo mai aver alcun slicing dell'oggetto; nel caso in
cui non si voglia ricorrere al polimorfismo o alle classi base astratte, l'unica strada è impedire la
copia di un oggetto.
L'object slicing viene evitato con il passaggio per reference dell'oggetto.
IMPEDIRE LA COPIA DI UN OGGETTO DI CLASSE BASE
Appunti di OOP in C++
francesco parisi telpar.altervista.org
Per prevenire che venga invocato un costruttore di copia, basta scriverne uno nella sezione privata
della classe base, una sola dichiarazione, senza nessuna implementazione. Es.
class B {
public:
B();
private:
B( const B& b );
}
In questo modo, quando sarà richiesto di creare un nuovo oggetto da uno esistente, il compilatore,
vedendo che c'è già un costruttore di copia, sebbene privato, non provvederà a invocarne uno di suo,
che, come noto, si limita a effettuare un bitcopy (la copia bit-a-bit dell'oggetto).
Dichiarando il costruttore di copia privato, quando verrà invocato dalla funzione verrà generato un
errore, in quanto non è pubblico, evitando così la copia.