2014-10-12 16 views
7

Ich möchte wissen, was das moderne C++ 11-Äquivalent von Javas instanceof. Ich habe dieses SO post gesehen, aber es ist ziemlich alt und fragte mich, ob es eine modernere, bessere Lösung in C++ 11 gibt?Was ist C++ 11 entspricht der Java-Instanz von

Ich hatte gehofft, dass es eine Möglichkeit gibt, ein Switch-Konstrukt zu verwenden, ohne auf eine manuelle Enum-Klasse zurückgreifen zu müssen.

class A { 

}; 

class B : public A { 

} 

class C : public A { 

} 

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

Meine Basisklasse hat keine virtuellen Methoden oder Funktionen. Ich repräsentiere einen Ausdrucksbaum für einen Parser und die Basisklasse ist nur ein polymorpher Halter - wie ein ADT in Haskell/OCaml.

+3

Fragen Sie nach 'dynamic_cast <>'? Das ist nicht C++ 11 spezifisch. –

+0

Nichts geändert: Es gibt keine Reflexion in Standard C++. Wenn Sie Informationen zum Laufzeittyp einschalten möchten, können Sie 'dynamic_cast' verwenden. – quantdev

+0

Vielleicht von Interesse: http://Stackoverflow.com/q/25495733/596781 –

Antwort

12

Die gleiche Antwort gilt nach wie vor, und hat, wie dies in C++ immer:

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

Diese Konstruktion A polymorph sein erfordert, das heißt virtuelle Member-Funktionen zu haben.

Beachten Sie auch, dass dieses Verhalten sich vom Vergleich typeid(obj) == typeid(C) unterscheidet, da letzterer auf exakte Typidentität testet, während der dynamische Cast sowie Java instanceof nur den Zieltyp als Basisklasse des Typs testen das am meisten abgeleitete Objekt.

+1

erfordert es auch 'RTTI', was für einige C++ - Benutzer ein wenig mühsam ist. – user2485710

+1

@ user2485710: Ich denke nicht, dass diese Aussage im Kontext der * Sprache * C++ sinnvoll ist. Der Code ist gültig C++, ohne Qualifikation. –

+1

Wenn Sie nicht "RTTI" haben, wird das Ding nicht funktionieren, ist egal, was Sie in Betracht ziehen, es ist nur erforderlich, um dieses Stück Code richtig funktionieren zu lassen. – user2485710

-1

Wenn Sie bereit sind, sich auf zur Kompilierungszeit bekannte Typen zu beschränken (anstatt Zeiger auf Instanzen von Klassen mit VTables zu verarbeiten), dann hat C++ 11 und höher ein instanceof Äquivalent: Es ist std::is_base_of.

Sie können auch überprüfen, std::is_convertible und std::is_same.

+3

Ich bin nicht sicher, wie das ihm hilft, wenn er es nicht zu einer Funktionsvorlage macht und die Typen zur Kompilierzeit kennt. Ich denke, es ist ziemlich klar, dass er über Laufzeit-Polymorphismus spricht. – PeterT

+0

@PeterT: stimme überhaupt nicht zu. Das heißt, in C++, besonders in Modern C++, machen wir sehr viel mit den bekannten Typen der Kompilierzeit, daher ist dies eine vollkommen gültige Antwort (auch wenn sie bearbeitet werden sollte). – einpoklum

0

In C++ haben einfache alte Daten (POD) keine Informationen zum Laufzeittyp. Die beschriebenen Klassen nehmen genau 1 Byte ein und haben in jedem Compiler mit der leeren Basisklassenoptimierung identische Laufzeitdarstellungen.

So was Sie wollen, kann nicht getan werden.

Das Hinzufügen eines virtuellen Destruktors zur Basisklasse wird in RTTI und dynamic_cast unterstützt.

Das Hinzufügen eines enum oder int Feldes zu der Basis, die für jede abgeleitete Klasse unterschiedlich initialisiert wird, funktioniert auch.

Eine weitere Option ist es, eine Template-Funktion zu erstellen, und einen Zeiger darauf speichern, etwa so:

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>;} 

und dann in geeigneter Weise ein my_type_id in A initialisiert zu speichern. Dadurch wird RTTI neu erfunden, und wenn Sie mehr Funktionen benötigen, werden Sie C++ RTTI-Overhead anwenden.

In C++ zahlen Sie nur für das, wonach Sie fragen: Sie können nach Klassen ohne RTTI fragen, was Sie getan haben, und es bekommen.

RTTI ist Laufzeittyp Information. POD ist einfache alte Daten, ein C++ 03 Begriff. Viele Klassen sind kein POD: Der einfache Weg besteht darin, einen Destruktor virtual hinzuzufügen. C++ 11 hat feinkörnigere Standardlayout- und Aggregatbegriffe.

Technisch sind RTTI und POD keine Gegensätze: Es gibt Klassen ohne RTTI, die nicht POD sind.

Beachten Sie, dass MSVC Optionen hat, RTTI nicht zu erzeugen und seine aggressive Comdat-Faltung kann die manuelle RTTI, die ich oben gemacht habe, brechen, in beiden Fällen in Verletzung des Standards.

-1

Tun Sie das nicht. In den meisten Fällen sollten Sie Ihr Design überprüfen, wenn Sie nach instanceof oder dynamic_cast fragen.

Warum? Sie verletzen höchstwahrscheinlich Liskov's substitiontin principle.

Wie dieser Ansatz:

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(); 
} 

Beachten Sie, dass als @Yakk Sie mindestens eine virtual Methode wies darauf hin, müssen ohnehin dynamische Polymorphie zu bekommen. Und es gibt eine Regel, die besagt: Wenn Sie mindestens eine virtuelle Methode haben, schreiben Sie immer auch einen virtuellen Destruktor in die Basisklasse.

Sie können all dies mit Vorlagen und Spezialisierung oder Typ Tagging tun, aber ich nehme von Ihrer Frage - aus Java kommen - Sie wollen noch nicht dorthin gehen. Sie wirklich wie virtuelle Methoden, nicht wahr? Entschuldigung, dass Sie sie in C++ markieren müssen.

+0

Ich glaube nicht, dass ein Programm, das aus 3 Klassen (A, B, C) besteht, gegen LSP verstößt und als gutes Design angesehen werden kann. Ich wollte downvote Ursache LSP Teil ist irreführend (die Frage ist über direkte Alternative zu instanceof für C++ 11 und Ihre Warnungen wurde bereits in den Link erwähnt), aber jemand kann es nützlich finden. – m039

Verwandte Themen