2014-07-20 13 views
5

In C++ possiamo convertire il puntatore classe figlio in parent, ma esiste un modo per riconvertirlo: da padre, che è stato ottenuto da figlio, restituire classe figlio?C++ Polymorphism: dalla classe padre al figlio

voglio dire:

class Parent 
{ 
    ... 
}; 

class Child : public Parent 
{ 
    ... 
}; 

int main(int argc, char const *argv[]) 
{ 
    Child* child = new Child(); 
    Parent* parent = child; 
    Child* old_child = parent; // how to do this?? 
    return 0; 
} 

Grazie per le vostre risposte.

+2

'Bambino * old_child = dynamic_cast (genitore);' – juanchopanza

+2

Sì. ['static_cast <>' e 'dynamic_cast <>'] (http://stackoverflow.com/questions/28002/regular-cast-vs-static-cast-vs-dynamic-cast) possono essere utilizzati per fare questo. –

+0

Grazie mille !!! – user2160982

risposta

9

"ma c'è un modo per riconvertirlo: dal genitore, che è stato ottenuto da bambino, restituire classe figlio?"

Sì, come indicato nelle altre risposte, ci sono due modi per farlo.

Child * old_child = dynamic_cast<Child*>(parent); 

Il risultato della dynamic_cast<> può essere controllato in fase di esecuzione, in tal modo è possibile determinare se l'oggetto parent rappresenta davvero un esempio Child:

if(!old_child) { 
    // parent is not a Child instance 
} 

Si noti inoltre per ottenere questo funziona correttamente, le classi la domanda deve avere un vtable, che RTTI possa effettivamente determinare la loro relazione.La forma più semplice per raggiungere questo obiettivo, sta dando la classe Parent una funzione distruttore virtuale

class Parent { 
public: 
    virtual ~Parent() {} 
    // or 
    // virtual ~Parent() = default; 
    // as suggested for latest standards 
}; 

NOTA:
Se questo dovesse applicarsi a una decisione generale di progettazione, vorrei fortemente non tenerne conto. Utilizzare invece pure virtual interfaces, che è garantito sia implementato o meno.


Il secondo modo di static_cast<> può essere utilizzato in ambienti, dove sanno bene che parent in realtà è un bambino. La forma più semplice di questo è la CRTP, dove Parent prende la classe che eredita come un parametro di template

template <class Derived> 
class Parent { 

    void someFunc() { 
     static_cast<Derived*>(this)->doSomething(); 
    } 
}; 

class Child : public Parent<Child> { 
public: 
    void doSomething(); 
}; 

La validità di un instatiation di Parent<> e static_cast<> saranno controllati al momento della compilazione.

NOTA:
Un altro vantaggio è che è possibile utilizzare un'interfaccia per derivata che fa uso di

  • membri della classe statici di Derived
  • typedef 's forniti da Derived
  • .. più tratti di classe, che possono essere controllati al momento della compilazione
+0

Il risultato di dynamic_cast può essere ... se la classe base è un vero tipo polimorfico, alias ha almeno una funzione o base virtuale.Altrimenti si degrada in static_cast (sarà ridotto in forza a static_cast quando, in ogni caso, è dimostrabilmente corretto). – Deduplicator

+0

@Deduplicator THX! Meglio ora? –

+1

Sì, +1. BTW: L'uso di '= default;' invece di '{}' per il corpo del dtor potrebbe essere leggermente più lungo ma non impedisce alla classe di essere banale, con tutti i benefici che ne derivano (anche se ha bisogno di un compilatore un po 'più moderno). – Deduplicator

2

È necessario cast l'oggetto di nuovo al bambino. Questo viene fatto in questo modo:

Child * old_child = static_cast<Child*>(parent); 

e

Child * old_child = dynamic_cast<Child*>(parent); 
+3

Ti dispiacerebbe spiegare un po 'di più sulle differenze e il comportamento effettivo di questi due metodi di cast. –

2
int main() { 
    Parent parent; 
    Child child; 

    // upcast - implicit type cast allowed 
    Parent *pParent = &child; 

    // downcast - explicit type case required 
    Child *pChild = (Child *) &parent; 
} 

si dovrebbe usare il dynamic_cast per farlo in modo sicuro:

Child *p = dynamic_cast<Child *>(pParent) 

EDIT

Con dynamic_cast restituisce un puntatore nullo se il tipo non fa parte della classe base, anche il casting su un riferimento genera un'eccezione bad_cast. dynamic_cast è particolarmente utile se non si conosce il tipo di oggetto.

D'altra parte static_cast:

Child *p = static_cast<Child *>(pParent) 

questo presuppone che si vuole invertire una conversione esplicita e non eseguono controlli runtime. Ciò consente flessibilità, ma deve essere usato con cautela.

L'abbattuto regolare indicato sopra:

Child *pChild = (Child *) &parent; 

È un C-stile giù cast (come un static_cast), che può anche lanciare ad una classe privata di base (non sono sicuro, l'ereditarietà multipla), mentre static_cast causerebbe un errore in fase di compilazione. Cose come conversioni numeriche sono un buon esempio per utilizzarle.

+0

risposta aggiornata per spiegare un po 'sui problemi di sicurezza –

0

risposte di cui sopra sono buone, concettualmente si può pensare in questo modo,

vostro Car oggetto che è derivata da Vehicle classe. È possibile fare riferimento a Car come Vehicle e convertirlo in Car come originariamente apparteneva allo Car. Ma sarà un problema se il tuo oggetto Vehicle rappresenta effettivamente Bike e prova a convertire in Car. Ecco perché hai bisogno di un casting sicuro.

class Vehicle 
{ 
    ... 
}; 

class Car : public Vehicle 
{ 
    ... 
}; 

class Bike : public Vehicle 
{ 
    ... 
}; 


int main(int argc, char const *argv[]) 
{ 
    Vehicle* vehicle = new Car(); 
    Car* old_car = dynamic_cast<Car *>(vehicle); 
    if(old_car) { 
     // OK Vehicle is Car, use it 
    } 

    vehicle = new Bike(); 
    old_car = dynamic_cast<Car *>(vehicle); 
    if(old_car) { 
     // No Vehicle isn't Car, this code won't execute 
    } 

    return 0; 
} 
+1

In che modo questa risposta aggiunge valore rispetto alle altre risposte, oltre a sostituire 'Parent' /' Child' con una metafora 'Vehicle' /' Car'? –

Problemi correlati