2012-07-16 20 views
11

Scott Meyer nel suo libro Effective C++ dice dynamic_cast viene utilizzato per eseguire calcoli di sicurezza verso il basso o attraverso una gerarchia di ereditarietà. Cioè, tu usi dynamic_cast per eseguire il cast di puntatori o riferimenti a oggetti di classe base in puntatori o riferimenti a oggetti di classe di base derivati ​​o fratelli in modo tale che tu possa determinare se i cast sono riusciti.Come identificare i cast falliti usando l'operatore dynamic_cast?

Le conversioni non riuscite sono indicate da un puntatore nullo (quando si esegue il cast dei puntatori) o un'eccezione (quando si esegue il cast dei riferimenti).

Vorrei ottenere due frammenti di codice che mostrano il cast fallito in caso di puntatore di lancio e il riferimento di casting può essere indicato.

+4

Stai chiedendo esempi di codice per verificare se un puntatore è nullo e il codice che rileva un'eccezione? –

+0

No. Non capisco come possano fallire i casting come menzionato da Scott. Un frammento di codice sarebbe sicuramente d'aiuto. –

+1

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

risposta

21

Per puntatori, si tratta di un semplice controllo nullo:

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

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

Per i riferimenti, si può prendere:

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

@LinuxPenseur Il controllo presuppone che "a" abbia un valore valido. Dovresti controllarlo prima (per l'allocazione). Il controllo dynamic_cast sta controllando se A può essere castato in modo sicuro su "B" - quindi il controllo è contro 'b' per' NULL' - cioè: b è nullo e a non è nullo. –

+0

@ReedCopsey: cosa si intende per "cast sicuro". In quale situazione può diventare NULL? –

+1

'dynamic_cast' viene utilizzato quando una classe è polimorfica (ha la funzione' virtuale') e esegue i controlli di runtime, restituendo un 'NULL'pointer. Usando 'dynamic_cast', stai dicendo di fare esattamente ciò che vuoi invece delle conversioni di tipo C in cui prova vari tipi di conversioni. 'dynamic_cast' viene anche usato quando non si conosce l'oggetto da convertire, invece di' static_cast' che viene usato per le classi non polimeriche e dove sono noti entrambi i tipi sulla conversione –

3

Basato sul commento del PO (" Io non capisco come calchi potrebbero fallire come citato da Scott. "), la vera domanda qui è veramente qualcosa del tipo:" come potrebbe un dynamic_cast fallire? "

Il tempo in cui si verifica un errore è quando il tipo di destinazione non corrisponde al tipo dinamico dell'oggetto. Per un semplice esempio:

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

Qui sebbene apotrebbe scegliere un oggetto di tipo B, in realtà fa scegliere un oggetto di tipo A. Quando proviamo a fare un dynamic_cast per farlo puntare a un B, questo fallisce. Nel secondo tentativo, abbiamo di nuovo un puntatore che non solo potrebbe ma fa puntare a un oggetto di tipo B. Dal momento che lo fa, il dynamic_cast a B * riesce in questo caso.

La situazione di base non cambia (molto) per il caso di riferimento, solo a, b e c diventano riferimenti al posto dei puntatori, e notiamo il fallimento con la cattura un'eccezione (che @ReedCopsey ha già dimostrato abbastanza bene che Non penso di avere nulla di nuovo da aggiungere).

3

Ecco un esempio completo che mostra come dynamic_cast non può produrre un puntatore.

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 
} 

Nel mondo reale sarete tentando di lanciare puntatori che non sono stati così creati semplicemente, forse provengono da un vector per esempio.