2013-05-07 6 views
13

L'affettamento di oggetti si verifica quando assegniamo o copiamo un oggetto di classe derivata a un oggetto della sua classe base, perdendo la parte derivata di esso nel processo.L'interscambio oggetti è mai utile?

È stato spiegato in modo più approfondito qui: What is the slicing problem in C++?.

(Me stesso, non vedo come un problema, piuttosto una conseguenza naturale della semantica di valore del linguaggio, ma non è questo il punto della questione.)

Quello che mi chiedo è: sono ci sono mai situazioni in cui lo useresti di proposito? Una situta in cui è lo "strumento giusto per il lavoro"?

+1

Eventuali duplicati: http://stackoverflow.com/questions/2389125/object-slicing-is-it-advantage – shivakumar

+0

@shivakumar grazie, bella scoperta. L'esempio nella risposta è costituito, però. Speravo che qualcuno potesse venire con un esempio del mondo reale. – jrok

risposta

5

Certo, può essere utile quando si desidera eliminare la porzione derivata della classe, magari per eliminare le dipendenze.

Ad esempio, diciamo che abbiamo una configurazione di sistema di oggetti in cui ogni base appartiene a un tipo derivato e ogni tipo derivato ha varie dipendenze, forse soddisfatte tramite l'iniezione di dipendenza. Potrebbe essere necessario creare un clone di una base, anche se potrebbe essere necessario assegnare un nuovo insieme di dipendenze per il tipo derivato effettivo di tale base.

Questo può essere paragonato a un motore di gioco in cui esistono molti tipi di collisori. Ogni collider deriva da un oggetto simile ad un'interfaccia di base in vari modi. Vogliamo clonare un collisore per recuperarne la posizione e la scala (dalla base), ma vogliamo posizionare un'implementazione derivata completamente diversa su questa base. "Affettare oggetti" potrebbe essere un modo semplice per raggiungere questo obiettivo.

In realtà un componente o un'organizzazione di oggetti aggregata avrebbe molto più senso rispetto all'oggetto di slicing specifico, ma è per lo più la stessa idea.

+0

Concettualmente, sembra che per ogni dato tipo la sostituibilità legata all'eredità sia generalmente significativa ad una particolare profondità di indiretta mutabile. Java e .NET presuppongono che, fatta eccezione per la sostituibilità delle matrici, si applichino a riferimenti singolarmente indiretti (un riferimento a sostituti 'derivati' per un riferimento a' base', ma ad esempio 'Elenco ' non sostituisce 'Elenco '). Direi che il "problema" di affettamento principale deriva dal fatto che i tipi che sono sostituibili direttamente non dovrebbero consentire sostituzioni single-indirette di riferimenti mutabili. – supercat

0

Alcune implementazioni STL utilizzano effettivamente oggetto affettare implementare algoritmi: ad esempio, utilizzando iterator_tags si può facilmente rendere std::advance utilizzare l'algoritmo più efficiente:

namespace std { 

template <class I> 
void advance_impl(I& it, int n, input_iterator_tag) { 
    for (; n > 0; --n) 
     ++it; 
} 

// Forward Iterators use the same implementation as Input Iterators... 

// TODO: 
// Add bidirectional_iterator_tag implementation... 

template <class I> 
void advance_impl(I& it, int n, random_access_iterator_tag) { 
    it += n; 
} 

template <class I> 
void advance(I& it, int n) { 
    advance_impl(it, n, typename iterator_traits<I>::iterator_category()); 
} 

} // std 

Utilizzando il proprio gerarchia di classi poco si può disambiguare altrimenti ambigua sovraccarichi di funzione. Per esempio. per convertire un oggetto in un std::string si potrebbe voler utilizzare la funzione membro dell'oggetto to_string() se esiste o altrimenti utilizzare operator<<.

struct R2 {};  // rank 2 
struct R1 : R2 {}; // rank 1 

// C++11. 
// Use some type traits and enable_if in C++03. 
template <class T> 
auto ToString(R1, T const& t) -> decltype(t.to_string()) { 
    return t.to_string(); 
} 

template <class T> 
std::string ToString(R2, T const& t) { 
    std::ostringstream s; 
    s << t; 
    return s.str(); 
} 

template <class T> 
std::string ToString(T const& t) { 
    return ToString(R1(), t); 
}