2014-10-12 12 views
7

Voglio sapere qual è il moderno equivalente di C++ 11 dell'istanza di Java. Ho visto questo SO post ma è piuttosto vecchio e mi chiedevo se c'è una soluzione più moderna e migliore in C++ 11?Qual è l'equivalente di C++ 11 dell'istanza di Java di

Speravo ci fosse la possibilità di utilizzare un costrutto switch senza dover ricorrere a una classe enum manuale.

class A { 

}; 

class B : public A { 

} 

class C : public A { 

} 

on_event(A& obj) 
{ 
    switch (obj) { 
     case A: 
     case B: 
     case C: 
    } 
} 

La mia classe base non ha metodi o funzioni virtuali. Sto rappresentando un albero di espressioni per un parser e la classe base è solo un supporto polimorfico - come un ADT in Haskell/OCaml.

+3

Stai chiedendo 'dynamic_cast <>'? Questo non è specifico per C++ 11. –

+0

Non è cambiato nulla: non c'è riflesso nel C++ standard. Se si desidera attivare le informazioni sul tipo di runtime, si 'dynamic_cast' – quantdev

+0

Forse di interesse: http://stackoverflow.com/q/25495733/596781 –

risposta

12

La stessa risposta applica ancora, ed è sempre stato così in C++:

if (C * p = dynamic_cast<C *>(&obj)) 
{ 
    // The type of obj is or is derived from C 
} 
else 
{ 
    // obj is not a C 
} 

Questa costruzione richiede A essere polimorfico, cioè avere funzioni membro virtuali.

noti inoltre che questo comportamento è diverso dal confronto typeid(obj) == typeid(C), dal momento che questi ultimi test per la precisa identità di tipo, mentre il cast dinamico, così come Java instanceof, unico test per il tipo di destinazione per essere una classe di base del tipo di l'oggetto più derivato.

+1

richiede anche 'RTTI', che è un po 'un problema per alcuni utenti C++. – user2485710

+1

@ user2485710: Non penso che l'affermazione abbia senso nel contesto del * linguaggio * C++. Il codice è C++ valido, senza qualificazione. –

+1

se non hai 'RTTI' quella cosa non funzionerà, non importa quello che stai considerando, è solo necessario per far funzionare bene quel codice. – user2485710

-1

Se si è disposti a limitarsi a tipi noti in fase di compilazione (anziché utilizzare i puntatori su istanze di classi con vtables), C++ 11 e versioni successive hanno un equivalente instanceof: È std::is_base_of.

Si potrebbe anche voler verificare std::is_convertible e std::is_same.

+3

Non sono sicuro di come questo lo aiuti a meno che non lo renda un modello di funzione e conosca i tipi in fase di compilazione. Penso che sia abbastanza chiaro che sta parlando del polimorfismo di runtime – PeterT

+0

@PeterT: completamente in disaccordo. Cioè, in C++, in particolare Modern C++, facciamo un sacco con tipi noti in fase di compilazione, quindi questa è una risposta perfettamente valida (anche se dovrebbe essere modificata). – einpoklum

0

In P ++, i vecchi dati (POD) non hanno informazioni sul tipo di runtime. Le classi descritte prendono esattamente 1 byte e hanno rappresentazioni runtime identiche in qualsiasi compilatore con l'ottimizzazione della classe base vuota.

Come tale ciò che si desidera non può essere fatto.

Aggiunta di un distruttore virtuale alla classe base aggiunta in RTTI e supporto dynamic_cast.

L'aggiunta di un campo o int alla base che viene inizializzata in modo diverso per ogni classe derivata funziona anche.

Un'altra opzione è quella di creare una funzione template, e memorizzare un puntatore ad esso, così:

using my_type_id=void(*)(); 
template<class>void get_my_type_id_helper(){}; 
template<class T> my_type_id get_my_type_id(){return get_my_type_id_helper<T>;} 

e memorizzando un my_type_id in A inizializzato appropriatamente. Questo sta reinventando RTTI e, dal momento che si desiderano più funzionalità, ci si avvicina al sovraccarico di C++ RTTI.

In C++ paghi solo quello che chiedi: puoi chiedere lezioni senza RTTI, cosa che hai fatto e ottenerlo.

RTTI è in esecuzione informazioni di tipo orario. Il POD è semplicemente vecchi dati, un termine C++ 03. Molte classi non sono POD: il modo più semplice è aggiungere un distruttore virtual. C++ 11 ha un layout standard a grana fine e termini aggregati.

Tecnicamente RTTI e POD non sono opposti l'uno all'altro: ci sono classi senza RTTI che non sono POD.

Nota che MSVC ha opzioni per non generare RTTI e il suo aggressivo piegamento di Comdat può rompere il RTTI manuale che ho fatto sopra, in entrambi i casi in violazione dello standard.

-1

Non farlo. Nella maggior parte dei casi è necessario rivedere il design quando si richiede instanceof o dynamic_cast.

Perché? Molto probabilmente stai violando lo Liskov's substitiontin principle.

Che ne dite di questo approccio:

class A { 
    public: 
    virtual void action(); 
    virtual ~A(); 
}; 

class B : public A { 
    public: void action() override; 
}; 

class C : public A { 
    public: void action() override; 
}; 

void on_event(A& obj) 
{ 
    obj.action(); 
} 

Nota che, come ha sottolineato @Yakk è necessario almeno un virtual metodo in ogni caso per ottenere il polimorfismo dinamico. E c'è una regola che dice: quando hai almeno un metodo virtuale, scrivi sempre un distruttore virtuale nella classe base.

Si può fare tutto questo con i modelli e la specializzazione o il tagging del tipo, ma prendo dalla tua domanda - proveniente da Java - non vuoi ancora andarci. Davvero come i metodi virtuali, vero? Scusa, devi contrassegnarli in C++.

+0

Non penso che un programma che consiste di 3 classi (A, B, C) viola LSP e può essere considerato un buon progetto. Volevo downvotare perché la parte LSP è fuorviante (la domanda riguarda l'alternativa diretta a instanceof per C++ 11 e i tuoi avvertimenti erano già menzionati nel link), ma qualcuno potrebbe trovarlo utile. – m039

Problemi correlati