2009-02-01 37 views

Antwort

169

Versuchen Sie es mit:

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

Dies erfordert Ihre Compiler RTTI-Unterstützung aktiviert zu haben.

EDIT: Ich hatte einige gute Kommentare zu dieser Antwort!

Jedes Mal, wenn Sie eine dynamic_cast (oder instanceof) verwenden müssen, sollten Sie sich fragen, ob es notwendig ist. Es ist generell ein Zeichen für schlechtes Design.

Typische Abhilfen setzt das besondere Verhalten für die Klasse, die Sie für auf der Basisklasse in eine virtuelle Funktion werden überprüft oder vielleicht die Einführung so etwas wie ein visitor, wo man ein bestimmtes Verhalten für Subklassen ohne Änderung der Schnittstelle (mit Ausnahme der Zugabe einführen kann die Besucher-Akzeptanz-Schnittstelle natürlich).

Wie bereits erwähnt, ist dynamic_cast nicht kostenlos. Ein einfacher und konsistent durchführender Hack, der die meisten (aber nicht alle Fälle) behandelt, ist im Grunde eine Enumeration, die alle möglichen Typen repräsentiert, die Ihre Klasse haben kann, und prüft, ob Sie die richtige gefunden haben.

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

Das ist nicht gut oo Design, aber es kann eine Abhilfe sein und ihre Kosten sind mehr oder weniger nur ein virtueller Funktionsaufruf. Es funktioniert auch unabhängig davon, ob RTTI aktiviert ist oder nicht.

Beachten Sie, dass dieser Ansatz nicht mehrere Ebenen der Vererbung unterstützt also, wenn Sie nicht vorsichtig sind Sie mit dem Code suchen so enden könnte:

// 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

Klasse muss mindestens eine virtuelle Methode dafür haben, um dies zu funktionieren – vava

+4

Das ist in der Regel der Fall, wenn Sie eine "instanceof" Prüfung – Laserallan

+7

Wenn Sie Wenn Sie instanceof verwenden müssen, ist in den meisten Fällen etwas mit Ihrem Design nicht in Ordnung. – 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

Das ist ein wirklich schlechtes Beispiel. Warum nicht überladen, das ist billiger? – user1095108

+8

Das Hauptproblem ist, dass es die Frage nicht beantwortet. 'instanceof' fragt den dynamischen Typ ab, aber in dieser Antwort stimmen der dynamische und der statische Typ immer überein. – MSalters

+0

@HHH Sie beantworten ist weit weg von der Frage, die gefragt wird! – programmer

26

Je nachdem, was Sie Sie tun möchten, Dazu könnte:

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

Verwendung:

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

Dies funktioniert jedoch nur mit den Typen, die der Compiler kennt.

Edit:

Dieser Code sollte für polymorphe Zeiger arbeiten:

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

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

+0

Elegante und gut gemachte Lösung. +1 Aber achten Sie darauf, den richtigen Zeiger zu bekommen. Nicht gültig für polymorphe Zeiger? –

+0

Was ist, wenn wir den Zeiger bei Verwendung dieser Funktion deferenziert haben? Würde es dann für polymorphe Zeiger funktionieren? –

+0

Nein, das funktioniert nur mit den Typen, die dem Compiler bekannt sind. Funktioniert nicht mit polymorphen Zeigern, unabhängig davon, ob Sie sie deaktivieren oder nicht. Ich werde etwas hinzufügen, das in diesem Fall funktionieren könnte. – panzi

-11

Das funktionierte perfekt für mich-Code mit :: Blocks IDE mit GCC Compiler

#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 bitte lesen Sie die Frage vor dem Posten einer Antwort. – programmer

+0

@programmer Ich denke du willst @pgp aufrufen, ich habe einfach seine Code Formatierung korrigiert. Auch seine Antwort scheint im Grunde genommen "use' typeid' "zu sein, was zwar falsch ist (" Es gibt keine Garantie, dass dieselbe std :: type_info-Instanz von allen Auswertungen des typeid-Ausdrucks auf demselben Typ angesprochen wird ... 'assert (typeid (A) == typeid (A));/* nicht garantiert * /' ", siehe [cppreference.com] (http://en.cppreference.com/w/cpp/language/typeid#Notes)), zeigt an, dass er zumindest versucht hat, die Frage zu beantworten, wenn auch nicht hilfreich, weil er es versäumt hat, ein minimales Arbeitsbeispiel anzubieten. –

+0

@Andreas, Entschuldigung! mein Schlechter, ich werde den Beitrag bearbeiten. – programmer

1

Es ist bekannt, dass dynamic_cast ineffizient ist. Sie durchläuft die Vererbungshierarchie und ist die einzige Lösung, wenn Sie mehrere Vererbungsebenen haben und prüfen müssen, ob ein Objekt eine Instanz eines der Typen in seiner Typhierarchie ist.

Aber wenn eine begrenztere Form von instanceof, die nur, wenn ein Objekt überprüft ist genau die Art Du viel effizienter angeben, reicht für Ihre Bedürfnisse, die Funktion unten wäre:

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

Hier ist ein Beispiel wie würden Sie die Funktion oben aufrufen:

DerivedA k; 
Base *p = &k; 

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

Sie Vorlagentyp A (als Typ, nach dem Sie die Überprüfung) angeben würde, und übergeben das Objekt, das Sie als das Argument testen wollen (aus dem Vorlagentyp K würde abgeleitet werden).