it-swarm.com.de

Den Typ eines Objekts in C++ ermitteln

Ich habe eine Klasse A und eine andere Klasse, die von ihr erbt, B. Ich überschreibe eine Funktion, die ein Objekt vom Typ A als Parameter akzeptiert, also muss ich ein A akzeptieren. Ich möchte also false zurückgeben und nicht fortfahren, wenn das übergebene Objekt nicht vom Typ B ist.

Was ist der beste Weg, um herauszufinden, welcher Typ das Objekt ist, das an meine Funktion übergeben wird?

128
lemnisca

dynamic_cast sollte den Trick tun 

TYPE& dynamic_cast<TYPE&> (object);
TYPE* dynamic_cast<TYPE*> (object);

Das Schlüsselwort dynamic_cast wandelt ein Datum von einem Zeiger oder Referenztyp in einen anderen um und führt eine Laufzeitüberprüfung durch, um die Gültigkeit der Umwandlung sicherzustellen.

Wenn Sie versuchen, einen Zeiger auf einen Typ umzuwandeln, der kein tatsächlicher Objekttyp ist, ist das Ergebnis der Umwandlung NULL. Wenn Sie versuchen, auf einen Typ umzuwandeln, der kein tatsächlicher Objekttyp ist, löst die Umwandlung eine bad_cast - Ausnahme aus.

Stellen Sie sicher, dass in der Base-Klasse mindestens eine virtuelle Funktion vorhanden ist, damit dynamic_cast funktioniert.

141
yesraaj

Dynamische Umwandlung ist das Beste für Ihre Problembeschreibung, Ich möchte jedoch hinzufügen, dass Sie den Klassentyp mit finden können:

#include <typeinfo>

...
string s = typeid(YourClass).name()
130
Robocide

Dies wird als RTTI bezeichnet, aber Sie möchten Ihr Design hier fast noch einmal überdenken, da das Auffinden des Typs und das Ausführen besonderer Dinge den Code spröder machen.

23
Paul Betts

Binden Sie in Ihren Objekten wahrscheinlich ein ID-Tag ein und verwenden Sie es, um zwischen Objekten der Klasse A und Objekten der Klasse B zu unterscheiden.

Dies zeigt jedoch einen Konstruktionsfehler. Idealerweise sollten die Methoden in B, die A nicht hat, Teil von A sein, aber leer gelassen werden, und B überschreibt sie. Dies macht den klassenspezifischen Code überflüssig und entspricht eher dem Geist von OOP. 

9
freespace

Suchen Sie nach dynamic_cast<B*>(pointer)?

7
Joshua

Der Vollständigkeit halber werde ich aus Robocide bauen und darauf hinweisen, dass typeid ohne name () alleine verwendet werden kann:

#include <typeinfo>
#include <iostream>

using namespace std;

class A {
public:
    virtual ~A() = default; // We're not polymorphic unless we
                            // have a virtual function.
};
class B : public A { } ;
class C : public A { } ;

int
main(int argc, char* argv[])
{
    B b;
    A& a = b;

    cout << "a is B: " << boolalpha << (typeid(a) == typeid(B)) << endl;
    cout << "a is C: " << boolalpha << (typeid(a) == typeid(C)) << endl;
    cout << "b is B: " << boolalpha << (typeid(b) == typeid(B)) << endl;
    cout << "b is A: " << boolalpha << (typeid(b) == typeid(A)) << endl;
    cout << "b is C: " << boolalpha << (typeid(b) == typeid(C)) << endl;
}

Ausgabe:

a is B: true
a is C: false
b is B: true
b is A: false
b is C: false
6
firebush

Weil Ihre Klasse nicht polymorph ist. Versuchen:

struct BaseClas { int base; virtual ~BaseClas(){} };
class Derived1 : public BaseClas { int derived1; };

Nun ist BaseClas polymorph. Ich habe die Klasse in struct geändert, da die Mitglieder einer struct standardmäßig öffentlich sind.

3
c64zottel

Wie von anderen angegeben, können Sie dynamic_cast verwenden. Die Verwendung von dynamic_cast zum Ermitteln des Typs der abgeleiteten Klasse, an der Sie arbeiten, weist im Allgemeinen auf das schlechte Design hin. Wenn Sie eine Funktion überschreiben, die einen Zeiger auf A als Parameter verwendet, sollte sie mit den Methoden/Daten der Klasse A selbst arbeiten können und nicht von den Daten der Klasse B abhängen. In Ihrem Fall, anstatt sie zu überschreiben Wenn Sie sicher sind, dass die Methode, die Sie schreiben, nur mit Klasse B funktioniert, sollten Sie eine neue Methode in Klasse B schreiben.

3
Naveen

Ihre Beschreibung ist etwas verwirrend. 

Im Allgemeinen, obwohl einige C++ - Implementierungen über Mechanismen verfügen, sollten Sie nicht nach dem Typ fragen. Stattdessen soll ein Dynamic_cast auf dem Zeiger auf A ausgeführt werden. Dies führt dazu, dass zur Laufzeit der tatsächliche Inhalt des Zeigers auf A geprüft wird. Wenn Sie ein B haben, erhalten Sie den Zeiger auf B. Andernfalls erhalten Sie eine Ausnahme oder eine Null.

2
Uri

Verwenden Sie überlastete Funktionen. Benötigt keine Unterstützung für dynamic_cast oder sogar RTTI:

class A {};
class B : public A {};

class Foo {
public:
    void Bar(A& a) {
        // do something
    }
    void Bar(B& b) {
        Bar(static_cast<A&>(b));
        // do B specific stuff
    }
};
1
jmucchiello

Wenn Sie auf die Boost-Bibliothek zugreifen können, benötigen Sie vielleicht die Funktion type_id_with_cvr (), die den Datentyp bereitstellen kann, ohne Modifizierer const, volatile, & und && . Hier ist ein einfaches Beispiel in C++ 11:

#include <iostream>
#include <boost/type_index.hpp>

int a;
int& ff() 
{
    return a;
}

int main() {
    ff() = 10;
    using boost::typeindex::type_id_with_cvr;
    std::cout << type_id_with_cvr<int&>().pretty_name() << std::endl;
    std::cout << type_id_with_cvr<decltype(ff())>().pretty_name() << std::endl;
    std::cout << typeid(ff()).name() << std::endl;
}

Hoffe das ist nützlich.

0
Kehe CAI