Wie kann ich überprüfen, ob ein Objekt der Typ eine bestimmte Unterklasse in C ++ ist?
-
08-07-2019 - |
Frage
Ich dachte nach dem Vorbild der typeid()
verwenden, aber ich weiß nicht, wie zu fragen, ob diese Art eine Unterklasse einer anderen Klasse ist (was, nebenbei gesagt, abstrakt ist)
Lösung
Sie sollten wirklich nicht. Wenn Ihr Programm wissen muss, welche Klasse ein Objekt ist, zeigt an, dass in der Regel einen Konstruktionsfehler. Sehen Sie, wenn Sie das Verhalten bekommen können Sie mit virtuellen Funktionen möchten. Auch weitere Informationen über das, was Sie versuchen würde helfen, zu tun.
Ich gehe davon aus 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 das, was Sie haben, dann versuchen Sie, so etwas zu tun:
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();
}
Edit: Da die Debatte über diese Antwort noch nach so vielen Jahren geht weiter, ich dachte, dass ich in einigen Referenzen werfen sollte. Wenn Sie einen Zeiger oder eine Referenz auf eine Basisklasse haben, und Ihr Code muss die abgeleitete Klasse des Objekts kennen, dann verletzt es Liskov Substitutionsprinzip . Uncle Bob diese ein als " Anathema Orientiertes Design Objekt".
Andere Tipps
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;
}
}
Sie können es mit dynamic_cast
tun (zumindest für polymorphe Typen).
Eigentlich auf dem zweiten Gedanken - man kann nicht sagen, ob es nämlich eine bestimmte Art mit dynamic_cast
ist -. Sie können jedoch sagen, ob es die Art oder eine Unterklasse davon ist
template <class DstType, class SrcType>
bool IsType(const SrcType* src)
{
return dynamic_cast<const DstType*>(src) != nullptr;
}
dynamic_cast
kann bestimmen, ob die Art der Zieltyp überall in der Vererbungshierarchie enthält (ja, es ist ein wenig bekanntes Merkmal, dass, wenn B
von A
und C
erbt, kann er eine A*
direkt in eine C*
drehen). typeid()
kann die genaue Art des Objekts bestimmen. Allerdings sollten diese beiden äußerst sparsam eingesetzt werden. Wie bereits erwähnt, sollten Sie immer dynamischer Typ Identifizierung werden vermieden, weil es ein Konstruktionsfehler anzeigt. (Auch, wenn Sie das Objekt kennen, ist sicher der Zieltyp Sie gesenkten mit einem static_cast
tun können. Boost-ein polymorphic_downcast
bietet, die einen niedergeschlagenen mit dynamic_cast
und assert
im Debug-Modus zu tun, und im Release-Modus wird es nur verwenden a static_cast
).
Ich bin nicht einverstanden, dass Sie sollten nie eine Objekttyp in C ++ überprüfen möchten. Wenn Sie es vermeiden kann, stimme ich zu, dass Sie sollten. Zu sagen, Sie sollten dies nie tun unter keinen Umständen allerdings zu weit geht. Sie können dies in sehr vielen Sprachen tun, und es kann Ihr Leben viel einfacher machen. Howard Pinsley zum Beispiel zeigte uns, wie in seinem Beitrag auf C #.
Ich mache viel Arbeit mit dem Qt-Framework. Im allgemeinen Modell, das ich, was ich tun sie nach der Art und Weise Dinge zu tun (zumindest, wenn sie in ihrem Rahmen arbeiten). Die QObject-Klasse ist die Basisklasse aller Qt-Objekte. Diese Klasse hat die Funktionen isWidgetType () und isWindowType () als eine schnelle Unterklasse überprüfen. Warum also nicht in der Lage sein, Ihre eigenen abgeleiteten Klassen zu überprüfen, was vergleichbar ist es die Natur ist? Hier ist ein QObject Spin-off von einigen dieser anderen Stellen:
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 ); }
};
Und dann, wenn du um einen Zeiger auf eine QObject sind vorbei, können Sie überprüfen, ob es auf der abgeleiteten Klasse zeigt durch die statische Member-Funktion aufrufen:
if( MyQObject::isThisType( qObjPtr ) ) qDebug() << "This is a MyQObject!";
Ich weiß nicht, ob ich das Problem richtig verstanden hat, so lassen Sie es mich in meinen eigenen Worten neu formulieren ...
Problem: (oder umgekehrt) Da Klassen B
und D
, festzustellen, ob D
eine Unterklasse von B
ist
Lösung: Verwenden Sie einige Vorlage Magie! Okay, ernsthaft müssen Sie bei LOKI einen Blick nehmen, eine ausgezeichnete Vorlage Meta-Programmierung Bibliothek, hergestellt von der sagenumwobenen C ++ Autor Andrei Alexandrescu.
Insbesondere herunterladen LOKI und umfassen Kopf TypeManip.h
davon im Quellcode verwendet dann die SuperSubclass
Klassenvorlage wie folgt:
if(SuperSubClass<B,D>::value)
{
...
}
Nach der Dokumentation wird SuperSubClass<B,D>::value
wahr sein, wenn B
eine öffentliche Basis von D
ist, oder wenn B
und D
ist Aliase des gleichen Typs.
d. entweder D
ist eine Unterklasse von B
oder D
die gleiche wie B
ist.
Ich hoffe, das hilft.
Bearbeiten
Bitte beachten Sie die Auswertung von SuperSubClass<B,D>::value
bei der Kompilierung geschieht im Gegensatz zu einigen Methoden, die dynamic_cast
verwenden, daher gibt es keine Strafe für die Verwendung dieses Systems zur Laufzeit.
#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:
IS A D22
IS A D2
IS A Base
Sie können es nur bei der Kompilierung-Vorlagen verwenden, es sei denn, Sie RTTI verwenden.
Damit können Sie die typeid Funktion benutzen, die einen Zeiger auf eine type_info Struktur ergeben wird, die Informationen über die Art enthält.
Lesen Sie, es unter Wikipedia
In c # können Sie einfach sagen:
if (myObj is Car) {
}
Ich dachte nach dem Vorbild des
typeid()
mit ...
typeid().name()
: Nun ja, könnte es durch einen Vergleich durchgeführt werden. Wenn wir die bereits beschriebene Situation, in:
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)
sei:
#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
}
}