2009-02-01 12 views

Odpowiedz

169

Spróbuj użyć:

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

Wymaga kompilatora mieć RTTI wsparcie włączona.

EDYCJA: Mam kilka dobrych komentarzy na temat tej odpowiedzi!

Za każdym razem, gdy trzeba użyć dynamic_cast (lub instanceof), lepiej zadać sobie pytanie, czy jest to konieczne. Jest to ogólnie oznaką złego projektu.

Typowe obejścia polegają na wprowadzeniu zachowania specjalnego dla klasy, do której się sprawdza, w funkcji wirtualnej na klasie bazowej lub wprowadzeniu czegoś takiego jak visitor, w którym można wprowadzić określone zachowanie dla podklas bez zmiany interfejsu (z wyjątkiem dodawania interfejs akceptacji odwiedzających oczywiście).

Jak wskazano, dynamic_cast nie przychodzi za darmo. Prostym i konsekwentnie wykonywanym hackem, który obsługuje większość (ale nie wszystkie przypadki), jest dodanie ekwipunku reprezentującego wszystkie możliwe typy, które może posiadać twoja klasa i sprawdzenie, czy masz właściwą.

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

To nie jest dobry z projektu, ale może to być obejście, a jej koszt jest mniej więcej tylko wirtualne wywołanie funkcji. Działa również niezależnie od RTTI jest włączona, czy nie.

Należy zauważyć, że takie podejście nie obsługuje wiele poziomów dziedziczenia, więc jeśli nie jesteś ostrożny może skończyć się kod wygląda tak:

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

musi mieć co najmniej jedną wirtualną metodę, aby to zadziałało – vava

+4

Zwykle tak jest, gdy wykonujesz test "instanceof" – Laserallan

+7

Jeśli muszą używać instanceof, w większości przypadków coś jest nie tak z twoim projektem. – 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

To jest naprawdę zły przykład. Dlaczego nie skorzystać z przeciążenia, czyli taniej? – user1095108

+8

Głównym problemem jest to, że nie odpowiada na pytanie. 'instanceof' pyta o typ dynamiczny, ale w tej odpowiedzi typ dynamiczny i statyczny zawsze odpowiadają. – MSalters

+0

@HHH odpowiesz jest o krok od pytania! – programmer

26

W zależności od tego, co chcesz zrobić ci może to zrobić:

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

Zastosowanie:

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

Jednak to działa wyłącznie na typach znanych kompilatorowi.

Edit:

Kod ten powinien działać na polimorficznych wskazówek:

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

Przykład: http://cpp.sh/6qir

+0

Eleganckie i dobrze wykonane rozwiązanie. +1 Ale uważaj, aby uzyskać prawidłowy wskaźnik. Nie dotyczy wskaźnika polimorficznego? –

+0

Co się stanie, jeśli wskażemy wskaźnik przy korzystaniu z tej funkcji? Czy wtedy działałoby na wskaźniki polimorficzne? –

+0

Nie działa to tylko na typach znanych kompilatorowi. Nie będzie działał z wskaźnikami polimorficznymi, bez względu na to, czy zniknąłeś, czy nie. Dodam coś, co może działać w tym przypadku. – panzi

-11

Ten pracował dla mnie idealny przy użyciu kodu :: Blocks IDE kompilator GCC z

#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 proszę przeczytać pytanie przed wysłaniem odpowiedzi. – programmer

+0

@programm Myślę, że masz na myśli wywołanie @pgp, po prostu naprawiłem jego formatowanie kodu. Ponadto, jego odpowiedź wydaje się być w zasadzie "use' typeid' ", która jest błędna (" Nie ma gwarancji, że ta sama instancja std :: type_info będzie odwoływać się do wszystkich ocen wyrażenia typu typid na tym samym typie ... 'assert (typeid (A) == typeid (A));/* nie jest gwarantowane * /' ", patrz [cppreference.com] (http://en.cppreference.com/w/cpp/language/typeid#Notes)), wskazuje, że przynajmniej próbował odpowiedzieć na to pytanie, jeśli nie jest to pomocne, ponieważ zaniedbał oferowanie minimalnego przykładu pracy. –

+0

@Andreas, przepraszam! moje złe, będę edytować post. – programmer

1

dynamic_cast jest znany jako nieefektywny. Przechodzi do hierarchii dziedziczenia i jest jedynym rozwiązaniem, jeśli masz wiele poziomów dziedziczenia i trzeba sprawdzić, czy obiekt jest instancją dowolnego typu w hierarchii typów.

Ale jeśli bardziej ograniczona forma instanceof że tylko sprawdza, czy dany przedmiot jest dokładnie typ określić, wystarczy do swoich potrzeb, funkcja poniżej byłoby dużo bardziej wydajny:

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

Oto przykład od tego, jak chcesz wywołać funkcję powyżej:

DerivedA k; 
Base *p = &k; 

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

można by określić rodzaj szablonu A (jako typ jesteś sprawdzanie) i przechodzą w obiekcie, który chcesz przetestować jako argument (z których szablon typu K można wywnioskować).