2012-07-16 5 views
11

Scott Meyer in seinem Buch Effective C++ sagt dynamic_cast wird verwendet, um sichere Casts nach unten oder über eine Vererbungshierarchie durchzuführen. Das heißt, Sie verwenden dynamic_cast, um Zeiger oder Verweise auf Basisklassenobjekte in Zeiger oder Verweise auf abgeleitete oder gleichgeordnete Basisklassenobjekte zu konvertieren, sodass Sie feststellen können, ob die Umwandlungen erfolgreich waren.Wie identifiziert man fehlgeschlagene Casts mit dem dynamic_cast Operator?

Fehlgeschlagene Umwandlungen werden durch einen Null-Zeiger (beim Umwandeln von Zeigern) oder eine Ausnahme (beim Umwandeln von Referenzen) angezeigt.

Ich möchte zwei Code-Snippet bekommen, die die fehlgeschlagene Besetzung im Fall von Casting-Pointer und Casting-Referenz angezeigt werden kann.

+4

Fragen Sie nach Beispielen für Code, der testet, ob ein Zeiger Null ist und Code, der eine Ausnahme abfängt? –

+0

Nein. Ich verstehe nicht, wie Abgüsse ausfallen könnten, wie von Scott erwähnt. Ein Code-Snippet würde definitiv helfen. –

+1

http://en.wikipedia.org/wiki/Dynamic_cast –

Antwort

21

für Zeiger, es ist ein einfacher Null-Check:

A* a = new A(); 
B* b = dynamic_cast<B*>(a); 

if (b == NULL) 
{ 
    // Cast failed 
} 

Für Referenzen, können Sie fangen:

try { 
    SomeType &item = dynamic_cast<SomeType&>(obj); 
} 
catch(const std::bad_cast& e) { 
    // Cast failed 
} 
+0

@LinuxPenseur Die Überprüfung geht davon aus, dass "a" einen gültigen Wert hat. Sie müssten das zuerst überprüfen (für die Zuweisung). Die Überprüfung von dynamic_cast überprüft, ob A sicher in "B" umgewandelt werden kann - also ist die Überprüfung gegen "b" für "NULL" - dh: b ist null und a ist nicht null. –

+0

@ReedCopsey: Was ist meine 'sichere Besetzung' gemeint? In welcher Situation kann b NULL werden? –

+1

'dynamic_cast' wird verwendet, wenn eine Klasse polymorph ist (hat' virtuelle' Funktion) und es Laufzeitprüfungen durchführt, die einen 'NULL'-Zeiger zurückgeben. Mit 'dynamic_cast' geben Sie an, dass Sie anstelle von C-Style-Conversions genau das tun möchten, was Sie möchten, wenn Sie verschiedene Arten von Conversions ausprobieren. 'dynamic_cast' wird auch verwendet, wenn Sie das zu konvertierende Objekt nicht kennen, anstelle von' static_cast', das für nicht-polymorphische Klassen verwendet wird und beide Typen der Konvertierung bekannt sind –

3

auf der Bemerkung des OP Basierend (“Ich verstehe nicht, wie Abgüsse ausfallen könnten als von Scott erwähnt. "), die eigentliche Frage hier ist wirklich etwas wie:" Wie könnte ein dynamic_cast scheitern? "

Die Zeit, die es fehlschlagen würde, wenn der Zieltyp nicht mit dem dynamischen Typ des Objekts übereinstimmt. Ein einfaches Beispiel:

struct A { 
    virtual ~A() {} 
}; 

class B : public A {}; 

int main() { 
    A *a = new A; 

    B *b = dynamic_cast<B *>(a); // should fail 
    if (b == NULL) 
     std::cout << "First cast failed.\n"; 

    A *c = new B; 
    b = dynamic_cast<B *>(c);  // should succeed 
    if (b == NULL) 
     std::cout << "Second cast failed.\n"; 
    return 0; 
} 

Hier obwohl akonnte Punkt auf ein Objekt vom Typ B, es tatsächlich tut Punkt auf ein Objekt vom Typ A. Wenn wir versuchen, eine dynamic_cast zu machen, um es auf eine B zu zeigen, schlägt das fehl. Im zweiten Versuch haben wir wieder einen Zeiger, der nicht nur sondern auf ein Objekt des Typs B zeigen konnte. Da dies der Fall ist, gelingt in diesem Fall der dynamic_cast zu B *.

Die Grundsituation ändert sich nicht (viel) für den Referenzfall, nur a, b und c werden Referenzen anstelle von Zeigern, und wir beachten Sie den Fehler durch eine Ausnahme zu kontrollieren (die @ReedCopsey bereits gut genug gezeigt, dass Ich glaube nicht, dass ich etwas Neues hinzuzufügen habe).

3

Hier ist ein vollständiges Beispiel, das zeigt, wie dynamic_cast einen Zeiger nicht erzeugen kann.

class A 
{ 
public: 
    virtual void Foo(); 
}; 

class B: public A 
{ 
}; 

class C: public A 
{ 
}; 

void test() 
{ 
    A a; 
    B b; 
    A* pA = &b; 
    B* pB = dynamic_cast<B*>(pA); // this works OK, returns the expected pointer 
    C* pC = dynamic_cast<C*>(pA); // this returns NULL because B isn't a C 
} 

In der realen Welt werden versuchen, Sie Zeiger zu werfen, die nicht so ohne weiteres erstellt wurden, vielleicht kommen sie von einem vector zum Beispiel.

Verwandte Themen