Ich habe typeid()
nach dem Prinzip der Verwendung gedacht, aber ich weiß nicht, wie ich fragen soll, ob dieser Typ eine Unterklasse einer anderen Klasse ist (die übrigens abstrakt ist).
c++
class
subclass
identification
Tschad
quelle
quelle
std::is_base_of
nicht wie gewünscht funktioniert. : 3Antworten:
Das solltest du wirklich nicht. Wenn Ihr Programm wissen muss, um welche Klasse es sich bei einem Objekt handelt, weist dies normalerweise auf einen Konstruktionsfehler hin. Überprüfen Sie, ob Sie mithilfe virtueller Funktionen das gewünschte Verhalten erzielen können. Außerdem würden weitere Informationen darüber, was Sie versuchen, helfen.
Ich gehe davon aus, dass Sie eine Situation wie diese haben:
class Base; class A : public Base {...}; class B : public Base {...}; void foo(Base *p) { if(/* p is A */) /* do X */ else /* do Y */ }
Wenn Sie dies haben, versuchen Sie Folgendes:
class Base { virtual void bar() = 0; }; class A : public Base { void bar() {/* do X */} }; class B : public Base { void bar() {/* do Y */} }; void foo(Base *p) { p->bar(); }
Bearbeiten: Da die Debatte über diese Antwort nach so vielen Jahren immer noch andauert, dachte ich, ich sollte einige Referenzen einbringen. Wenn Sie einen Zeiger oder Verweis auf eine Basisklasse haben und Ihr Code die abgeleitete Klasse des Objekts kennen muss, verstößt er gegen das Liskov-Substitutionsprinzip . Onkel Bob nennt dies ein " Anathema für objektorientiertes Design ".
quelle
class Base { public: virtual ~Base() {} }; class D1: public Base {}; class D2: public Base {}; int main(int argc,char* argv[]); { D1 d1; D2 d2; Base* x = (argc > 2)?&d1:&d2; if (dynamic_cast<D2*>(x) == nullptr) { std::cout << "NOT A D2" << std::endl; } if (dynamic_cast<D1*>(x) == nullptr) { std::cout << "NOT A D1" << std::endl; } }
quelle
dynamic_cast<>
hier? Wäre das nichtstatic_cast<>
genug?x
beim Kompilieren angeben? Wenn ja, dannstatic_cast<>()
würde es funktionieren. Wenn Sie die Art derx
bis zur Laufzeit nicht sagen können, dann brauchen Siedynamic_cast<>()
Sie können es mit tun
dynamic_cast
(zumindest für polymorphe Typen).Beim zweiten Gedanken - Sie können nicht sagen, ob es sich SPEZIELL um einen bestimmten Typ
dynamic_cast
handelt - können Sie jedoch feststellen, ob es sich um diesen Typ oder eine Unterklasse davon handelt.template <class DstType, class SrcType> bool IsType(const SrcType* src) { return dynamic_cast<const DstType*>(src) != nullptr; }
quelle
std::is_polymorphic_v<T>
istfalse
.Der folgende Code zeigt drei verschiedene Möglichkeiten:
#include <iostream> #include <typeinfo> #include <typeindex> enum class Type {Base, A, B}; class Base { public: virtual ~Base() = default; virtual Type type() const { return Type::Base; } }; class A : public Base { Type type() const override { return Type::A; } }; class B : public Base { Type type() const override { return Type::B; } }; int main() { const char *typemsg; A a; B b; Base *base = &a; // = &b; !!!!!!!!!!!!!!!!! Base &bbb = *base; // below you can replace base with &bbb and get the same results // USING virtual function // ====================== // classes need to be in your control switch(base->type()) { case Type::A: typemsg = "type A"; break; case Type::B: typemsg = "type B"; break; default: typemsg = "unknown"; } std::cout << typemsg << std::endl; // USING typeid // ====================== // needs RTTI. under gcc, avoid -fno-rtti std::type_index ti(typeid(*base)); if (ti == std::type_index(typeid(A))) { typemsg = "type A"; } else if (ti == std::type_index(typeid(B))) { typemsg = "type B"; } else { typemsg = "unknown"; } std::cout << typemsg << std::endl; // USING dynamic_cast // ====================== // needs RTTI. under gcc, avoid -fno-rtti if (dynamic_cast</*const*/ A*>(base)) { typemsg = "type A"; } else if (dynamic_cast</*const*/ B*>(base)) { typemsg = "type B"; } else { typemsg = "unknown"; } std::cout << typemsg << std::endl; }
Das obige Programm druckt Folgendes:
quelle
dynamic_cast
kann bestimmen, ob der Typ den Zieltyp irgendwo in der Vererbungshierarchie enthält (ja, es ist eine wenig bekannte Funktion, die, wenn erB
vonA
und erbtC
, einenA*
direkt in einen verwandeln kannC*
).typeid()
kann den genauen Typ des Objekts bestimmen. Beide sollten jedoch äußerst sparsam eingesetzt werden. Wie bereits erwähnt, sollten Sie die dynamische Typidentifikation immer vermeiden, da dies auf einen Konstruktionsfehler hinweist. (Wenn Sie wissen, dass das Objekt sicher vom Zieltyp ist, können Sie einen Downcast mit astatic_cast
ausführen. Boost bietetpolymorphic_downcast
einen Downcast mitdynamic_cast
undassert
im Debug-Modus und im Release-Modus wird nur a verwendet.static_cast
)quelle
Ich bin nicht der Meinung, dass Sie niemals den Typ eines Objekts in C ++ überprüfen möchten. Wenn Sie es vermeiden können, stimme ich zu, dass Sie sollten. Zu sagen, dass Sie dies NIEMALS tun sollten, geht jedoch zu weit. Sie können dies in sehr vielen Sprachen tun, und es kann Ihr Leben viel einfacher machen. Howard Pinsley zum Beispiel hat uns in seinem Beitrag auf C # gezeigt, wie es geht.
Ich arbeite viel mit dem Qt Framework. Im Allgemeinen modelliere ich meine Arbeit nach der Art und Weise, wie sie Dinge tun (zumindest wenn ich in ihrem Rahmen arbeite). Die QObject-Klasse ist die Basisklasse aller Qt-Objekte. Diese Klasse hat die Funktionen isWidgetType () und isWindowType () als schnelle Unterklassenprüfung. Warum also nicht in der Lage sein, Ihre eigenen abgeleiteten Klassen zu überprüfen, was seiner Natur nach vergleichbar ist? Hier ist ein QObject-Spin-off einiger dieser anderen Beiträge:
class MyQObject : public QObject { public: MyQObject( QObject *parent = 0 ) : QObject( parent ){} ~MyQObject(){} static bool isThisType( const QObject *qObj ) { return ( dynamic_cast<const MyQObject*>(qObj) != NULL ); } };
Wenn Sie dann einen Zeiger auf ein QObject übergeben, können Sie überprüfen, ob er auf Ihre abgeleitete Klasse verweist, indem Sie die statische Elementfunktion aufrufen:
if( MyQObject::isThisType( qObjPtr ) ) qDebug() << "This is a MyQObject!";
quelle
Ich weiß nicht, ob ich Ihr Problem richtig verstehe, also lassen Sie es mich in meinen eigenen Worten wiederholen ...
Problem: Geben Sie bei gegebenen Klassen
B
und anD
, obD
es sich um eine Unterklasse von handeltB
(oder umgekehrt?).Lösung: Verwenden Sie etwas Vorlagenmagie! Okay, im Ernst, Sie müssen sich LOKI ansehen, eine hervorragende Meta-Programmierbibliothek für Vorlagen, die vom legendären C ++ - Autor Andrei Alexandrescu erstellt wurde.
Laden Sie LOKI herunter und fügen Sie den Header
TypeManip.h
daraus in Ihren Quellcode ein. Verwenden Sie dann dieSuperSubclass
Klassenvorlage wie folgt:if(SuperSubClass<B,D>::value) { ... }
Laut Dokumentation
SuperSubClass<B,D>::value
gilt, obB
es sich um eine öffentliche BasisD
handelt oder obB
undD
Aliase des gleichen Typs sind.dh entweder
D
ist eine Unterklasse vonB
oderD
ist die gleiche wieB
.Ich hoffe das hilft.
bearbeiten:
Bitte beachten Sie, dass die Auswertung von
SuperSubClass<B,D>::value
zur Kompilierungszeit erfolgt, im Gegensatz zu einigen Methoden, die verwendetdynamic_cast
werden. Daher gibt es keine Strafe für die Verwendung dieses Systems zur Laufzeit.quelle
#include <stdio.h> #include <iostream.h> class Base { public: virtual ~Base() {} template<typename T> bool isA() { return (dynamic_cast<T*>(this) != NULL); } }; class D1: public Base {}; class D2: public Base {}; class D22: public D2 {}; int main(int argc,char* argv[]); { D1* d1 = new D1(); D2* d2 = new D2(); D22* d22 = new D22(); Base* x = d22; if( x->isA<D22>() ) { std::cout << "IS A D22" << std::endl; } if( x->isA<D2>() ) { std::cout << "IS A D2" << std::endl; } if( x->isA<D1>() ) { std::cout << "IS A D1" << std::endl; } if(x->isA<Base>() ) { std::cout << "IS A Base" << std::endl; } }
Ergebnis:
quelle
Sie können dies nur zur Kompilierungszeit mithilfe von Vorlagen tun, es sei denn, Sie verwenden RTTI.
Hiermit können Sie die Funktion typeid verwenden, die einen Zeiger auf eine type_info-Struktur liefert, die Informationen zum Typ enthält.
Lesen Sie es bei Wikipedia nach
quelle
In c # kann man einfach sagen:
if (myObj is Car) { }
quelle
Nun ja, es könnte durch Vergleichen von :
typeid().name()
. Wenn wir die bereits beschriebene Situation annehmen, wo:class Base; class A : public Base {...}; class B : public Base {...}; void foo(Base *p) { if(/* p is A */) /* do X */ else /* do Y */ }
Eine mögliche Implementierung von
foo(Base *p)
wäre:#include <typeinfo> void foo(Base *p) { if(typeid(*p) == typeid(A)) { // the pointer is pointing to the derived class A } else if (typeid(*p).name() == typeid(B).name()) { // the pointer is pointing to the derived class B } }
quelle