2009-02-01 16 views

risposta

169

Provare a utilizzare:

if(NewType* v = dynamic_cast<NewType*>(old)) { 
    // old was safely casted to NewType 
    v->doSomething(); 
} 

Ciò richiede il compilatore per avere il supporto RTTI abilitato.

MODIFICA: Ho avuto alcuni buoni commenti su questa risposta!

Ogni volta che è necessario utilizzare un dynamic_cast (o instanceof) è meglio chiedersi se è una cosa necessaria. In genere è un segno di design scadente.

soluzioni tipiche sta mettendo il comportamento speciale per la classe che si sta verificando per in una funzione virtuale nella classe base, o forse l'introduzione di qualcosa di simile a un visitor in cui è possibile introdurre comportamenti specifici per le sottoclassi senza cambiare l'interfaccia (tranne che per l'aggiunta del interfaccia di accettazione del visitatore, naturalmente).

Come sottolineato, dynamic_cast non viene fornito gratuitamente. Un hack semplice e coerente che gestisce la maggior parte (ma non tutti i casi) è fondamentalmente l'aggiunta di una enumerazione che rappresenta tutti i possibili tipi che la tua classe può avere e controlla se hai ottenuto quello giusto.

if(old->getType() == BOX) { 
    Box* box = static_cast<Box*>(old); 
    // Do something box specific 
} 

Questo non è un buon design oo, ma può essere una soluzione e il suo costo è più o meno solo una chiamata di funzione virtuale. Funziona anche indipendentemente dal fatto che RTTI sia abilitato o meno.

Si noti che questo approccio non supporta più livelli di ereditarietà, quindi se non stai attento si potrebbe finire con il codice simile a questo:

// Here we have a SpecialBox class that inherits Box, since it has its own type 
// we must check for both BOX or SPECIAL_BOX 
if(old->getType() == BOX || old->getType() == SPECIAL_BOX) { 
    Box* box = static_cast<Box*>(old); 
    // Do something box specific 
} 
+0

deve avere almeno un metodo virtuale per farlo funzionare – vava

+4

Questo è generalmente il caso quando si esegue un controllo "instanceof" – Laserallan

+7

Se si usare instanceof, nella maggior parte dei casi c'è qualcosa di sbagliato nel tuo progetto. – mslot

-4
#include <iostream.h> 
#include<typeinfo.h> 

template<class T> 
void fun(T a) 
{ 
    if(typeid(T) == typeid(int)) 
    { 
    //Do something 
    cout<<"int"; 
    } 
    else if(typeid(T) == typeid(float)) 
    { 
    //Do Something else 
    cout<<"float"; 
    } 
} 

void main() 
{ 
     fun(23); 
     fun(90.67f); 
} 
+0

Questo è un pessimo esempio. Perché non usare il sovraccarico, che è più economico? – user1095108

+8

Il problema principale è che non riesce a rispondere alla domanda. 'instanceof' interroga il tipo dinamico, ma in questa risposta il tipo dinamico e statico corrisponde sempre. – MSalters

+0

@HHH la tua risposta è molto lontana dalla domanda che ti viene posta! – programmer

26

A seconda di cosa si vuole fare voi potrebbe fare questo:

template<typename Base, typename T> 
inline bool instanceof(const T*) { 
    return std::is_base_of<Base, T>::value; 
} 

Usa:

if (instanceof<BaseClass>(ptr)) { ... } 

Tuttavia, questo funziona esclusivamente sui tipi come noto dal compilatore.

Edit:

Questo codice dovrebbe funzionare per i puntatori polimorfici:

template<typename Base, typename T> 
inline bool instanceof(const T *ptr) { 
    return dynamic_cast<const Base*>(ptr) != nullptr; 
} 

Esempio: http://cpp.sh/6qir

+0

Soluzione elegante e ben fatta. +1 Ma fai attenzione a ottenere il puntatore corretto. Non valido per il puntatore polimorfico? –

+0

Cosa succede se abbiamo deferenziato il puntatore quando si utilizza questa funzione? Potrebbe quindi funzionare per i puntatori polimorfici? –

+0

No, funziona solo sui tipi noti al compilatore. Non funzionerà con i puntatori polimorfici, non importa se si derefernece o no. Aggiungerò qualcosa che potrebbe funzionare in quel caso però. – panzi

-11

questo ha funzionato perfetto per me usando Code :: Blocks IDE con GCC complier

#include<iostream> 
#include<typeinfo> 
#include<iomanip> 
#define SIZE 20 
using namespace std; 

class Publication 
{ 
protected: 
    char title[SIZE]; 
    int price; 

public: 
    Publication() 
    { 
     cout<<endl<<" Enter title of media : "; 
     cin>>title; 

     cout<<endl<<" Enter price of media : "; 
     cin>>price; 
    } 

    virtual void show()=0; 
}; 

class Book : public Publication 
{ 
    int pages; 

public: 
    Book() 
    { 
     cout<<endl<<" Enter number of pages : "; 
     cin>>pages; 
    } 

    void show() 
    { 
     cout<<endl<<setw(12)<<left<<" Book Title"<<": "<<title; 
     cout<<endl<<setw(12)<<left<<" Price"<<": "<<price; 
     cout<<endl<<setw(12)<<left<<" Pages"<<": "<<pages; 
     cout<<endl<<" ----------------------------------------"; 
    } 
}; 

class Tape : public Publication 
{ 
    int duration; 

public: 
    Tape() 
    { 
     cout<<endl<<" Enter duration in minute : "; 
     cin>>duration; 
    } 

    void show() 
    { 
     cout<<endl<<setw(10)<<left<<" Tape Title"<<": "<<title; 
     cout<<endl<<setw(10)<<left<<" Price"<<": "<<price; 
     cout<<endl<<setw(10)<<left<<" Duration"<<": "<<duration<<" minutes"; 
     cout<<endl<<" ----------------------------------------"; 
    } 
}; 
int main() 
{ 
    int n, i, type; 

    cout<<endl<<" Enter number of media : "; 
    cin>>n; 

    Publication **p = new Publication*[n]; 
    cout<<endl<<" Enter "<<n<<" media details : "; 

    for(i=0;i<n;i++) 
    { 
     cout<<endl<<" Select Media Type [ 1 - Book/2 - Tape ] "; 
     cin>>type; 

     if (type == 1) 
     { 
      p[i] = new Book(); 
     } 
     else 
     if (type == 2) 
     { 
      p[i] = new Tape(); 
     } 
     else 
     { 
      i--; 
      cout<<endl<<" Invalid type. You have to Re-enter choice"; 
     } 
    } 

    for(i=0;i<n;i++) 
    { 
     if (typeid(Book) == typeid(*p[i])) 
     { 
      p[i]->show(); 
     } 
    } 

    return 0; 
} 
+0

@Andres si prega di leggere la domanda prima di inviare una risposta. – programmer

+0

@programmer Penso che tu intenda chiamare @pgp, ho semplicemente corretto la sua formattazione del codice. Inoltre, la sua risposta sembra essere fondamentalmente "use' typeid' ", che mentre è sbagliato (" Non vi è alcuna garanzia che la stessa istanza di std :: type_info venga chiamata da tutte le valutazioni dell'espressione typeid sullo stesso tipo ... 'assert (typeid (A) == typeid (A));/* not guaranteed * /' ", vedi [cppreference.com] (http://en.cppreference.com/w/cpp/language/typeid#Notes)), indica che ha tentato almeno di rispondere alla domanda, se inutilmente, perché ha trascurato di offrire un esempio di lavoro minimo. –

+0

@Andreas, mi dispiace! il mio male, modificherò il post. – programmer

1

dynamic_cast è noto per essere inefficiente. Attraversa la gerarchia dell'ereditarietà e è l' l'unica soluzione se si dispone di più livelli di ereditarietà e occorre verificare se un oggetto è un'istanza di uno qualsiasi dei tipi nella relativa gerarchia di tipi.

Ma se una forma più limitata di instanceof che controlla solo se un oggetto è esattamente il tipo specificato, è sufficiente per le vostre esigenze, la funzione di sotto sarebbe molto più efficiente:

template<typename T, typename K> 
inline bool isType(const K &k) { 
    return typeid(T).hash_code() == typeid(k).hash_code(); 
} 

Ecco un esempio di come ci si richiama la funzione di cui sopra:

DerivedA k; 
Base *p = &k; 

cout << boolalpha << isType<DerivedA>(*p) << endl; // true 
cout << boolalpha << isType<DerivedB>(*p) << endl; // false 

Faresti specificare modello tipo A (come il tipo che stai controllando per), e passare l'oggetto che si desidera verificare come argomento (da cui tipo di modello K sarebbe dedotto).