Newsgroup: it.comp.lang.c++
Titolo: Aiuto con i casting

Sto studiando i 4 tipi di casting del c++, ma non mi sono ben chiare le
differenze. Qualcuno può spiegarli in maniera chiara, magari con riferimenti
pratici? Grazie mille,
_
SiSkO
SoS Game Developers: 
www.multiplayer.it/sos

pratici? Grazie mille,
Allora... in C++ e` possibile eseguire un cast esplicito in diversi 
modi...
reinterpret_cast<T>(arg)
e` equivalente ai cast C-style e serve a mappare sui bit
memorizzati in arg il tipo T. Il risultato e` chiaramente
dipendente dalla piattaforma su cui operi.
Esempio
int a = 0x2345f
int* Ptr = reinterpret_cast<int*>(a);
char C = reinterpret_cast<char>(a);
Lo stesso effetti lo si potrebbe ottenere anche con le union
(almeno su certe piattaforme)
union MyUnion {
  int a;
  int* Ptr;
  char C;
};
const_cast<T>(arg);
semplicemente rimuove tutte le occorrenze di cost e volatile
nel tipo di arg. T e arg devono essere lo stesso tipo a meno di
occorrenze di const e volatile.
const char* a = ...
char* b = const_cast<char*>(a);
static_cast<T>(arg)
Da usare quando si e` sicuri che
l'operazione e` corretta (ad esempio nelle conversioni da
puntatore a classe derivata a puntatore a classe base).
int a = 10;
long b = const_cast<long>(a);
dynamic_cast<T>(arg)
da usare per convertire un puntatore o un reference a classe
base in puntatore o reference a classe derivata quando l'operazione
puo` fallire (perche` arg non punta ad una istanza di classe derivata).
In questo caso il cast viene eseguito sempre a run-time verificando
che l'operazione sia lecita (mediante RTTI). Se l'operazione fallisce
viene restituito 0 per cast a puntatore, viene invece sollevata
una eccezione (mi pare bad_cast)
Derived* d = new Derived;
Base* b = new Base;
Base* c = d;
Derived* DPtr = dynamic_cast<Derived*>(b);
// L'operazione fallisce DPtr==0
Derived* DPtr = dynamic_cast<Derived*>(c);  // Ok
Paolo
P.s.
  Questa la mettiamo nella faq!
-----------------------------------------------
  Paolo Marotta
  Computer Science, University of Pisa
  home:   
http://www.cli.di.unipi.it/~marotta
-----------------------------------------------

Chiaro, grazie di tutto.

 pratici? Grazie mille,
reinterpret_cast: prende un dato argomento come pura sequenza
    di bit e re-interpreta quegli stessi bit come corrispondenti ad un
    diverso tipo di dato.  Operazione di bassissimo livello, mai
    portatile, tipica del "codice di sistema" (se la si trova a livello
    di "codice applicativo" e` un pessimo segno!-)
const_cast: serve esclusivamente per mettere e togliere i
    modificatori const e volatile ad un oggetto, o puntatore.
    Caso tipico: devo, ad esempio, implementare la funzione
    di signature:
    char* strchr(const char* s, char c);
    (signature malnata, ma e` quella prevista dallo standard
    C...:-); come faccio?  La risposta e` const_cast -- se ho,
    ad esempio, gia` a disposizione una
        char* strchr(char* s, char c);
    potro` semplicemente scrivere:
        char* strchr(const char* s, char c) {
            return strchr(const_cast<char*>(s),c);
        }
static_cast: e` il caso piu` normale di trasformazione di tipi;
    permette di applicare esplicitamente qualsiasi trasformazione
    che sarebbe applicata anche implicitamente, e anche le
    inverse di queste trasformazioni implicite.
    Ad esempio, supponi che io abbia gia` a disposizione una
    funzione
        double pippolo(double d);
    e mi viene chiesto di implementarne una di signature
        int pippolo(int i);
    la cui semantica e` eguale alla precedente (anche se
    magari potrei ottimizzare di piu` il caso intero, ma per
    ora voglio solo fare una implementazione di minima):
        int pippolo(int i) {
            return pippolo(static_cast<double>(i));
        }
    Avrei potuto applicare lo static_cast anche al valore
    di ritorno, ma non occorre, qui la trasformazione da
    double a int e` implicitamente equivalente ad esso.
    Viceversa per l'argomento mi serve, se avessi scritto
    solo "return pippolo(i)" avrei avuto una mala recursione.
dynamic_cast: serve esclusivamente su puntatori o reference
    a oggetti polimorfi, per "navigare" il grafo delle eredita`
    (o, caso particolare, per ottenere il valore come void*
    del puntatore all'intero oggetto, ma questo tipicamente
    e` un problema solo da "codice di sistema").
    Applicata ad un puntatore, tornera` puntatore nullo se
    la classe di runtime dell'oggetto non e` del tipo richiesto;
    applicata ad una reference, in situazione analoga causa
    invece un'eccezione.
    Tutti gli altri cast sono determinati a compile-time (anche
    se la conversione fra numeri interi e reali puo` eseguire
    un modesto ma non trascurabile tot di operazioni macchina),
    questo invece tipicamente e` piuttosto "pesino" a run-time.
    Un uso tipico e` risalire da un puntatore a classe-base alla
    classe derivata da cui si sa, o si crede, possa in realta`
    derivare la run-time class dell'oggetto; l'altro, analogo, e`
    il passaggio "laterale" fra rami diversi di una eredita`
    multipla.
    Ad esempio, date:
        class plutabile {
        public: virtual void pluto() = 0;
        };
        class pippabile {
        public: virtual void pippo() = 0;
        };
    Si ha la specifica di una funzione:
        void p_and_p(pippabile* p);
    che deve: chiamare il membro pippo di *p,
    poi, se e solo se l'oggetto passato e` anche
    plutabile, allora chiamarne anche il membro
    pluto.  Soluzione:
        void p_and_p(pippabile* p) {
            p->pippo();
            if(plutabile q = dynamic_cast<plutabile*>(p))
                q->pluto;
        }
I "riferimenti pratici" dovranno aspettare un eventuale
prosieguo di discussione perche` questo post mi pare
gia` lunghetto anzicheno`:-).
Alex