2012-09-20 19 views
9

Qualcuno può spiegare il comportamento del seguente codice?Indirizzi, reinterpret_cast e ereditarietà multipla

  1. Perché dobbiamo b = 3 nel primo caso, vale a dire b2 == &d è vero?
  2. Perché è giusto nel caso 2? Ho stampato gli indirizzi di b2 e d e sono diversi.
#include <iostream> 

using namespace std; 

class A 
{ 
public: 
    A() : m_i(0) { } 

protected: 
    int m_i; 
}; 

class B 
{ 
public: 
    B() : m_d(0.0) { } 

protected: 
    double m_d; 
}; 

class C 
    : public A 
    , public B 
{ 
public: 
    C() : m_c('a') { } 

private: 
    char m_c; 
}; 

int main() 
{ 
    C d; 
    B *b2 = &d; 

    cout << &d << endl; 
    cout << b2 << endl; 

    const int b = (b2 == &d) ? 3 : 4; ///Case1: b = 3; 
    const int c = (reinterpret_cast<char*>(b2) == reinterpret_cast<char*>(&d)) ? 3 : 4; //Case 2: c = 4; 

    std::cout << b << c << std::endl; 

    return 0; 
} 
+0

+1, solo perché questo è un buon esempio e illustra gli effetti dell'eredità multipla sui puntatori piuttosto bene – ltjax

+0

+1 allo stesso modo. un grande esempio, specialmente con nessun virtual in là per inviare veramente le persone attraverso la suoneria. – WhozCraig

risposta

9

d è di tipo C. Quando si converte un puntatore a C a un puntatore a B, è regolato in modo che esso punti al subobject B di C (come ajustement è necessario in generale con ereditarietà multipla, se nessuno era necessario per B, ce ne sarebbe uno per A come C eredita da entrambi A e B). Quindi al momento dell'assegnazione e del confronto, l'adeguamento è fatto.

Alle altre due volte, & d viene convertito a uno void * (implicitamente) o char * (con un reinterpret_cast) e nessun aggiustamento è fatto (lei ha chiesto in modo esplicito per nessuna regolazione con il reinterpret_cast e non v'è alcun motivo per effettuare un aggiustamento durante la conversione in vuoto *, complicherebbe solo il viaggio di andata e ritorno senza una buona ragione, avresti di nuovo un risultato simile per A), quindi la rappresentazione è diversa.

BTW, se si fosse utilizzato reinterpret_cast<B*>(&d), nessuna regolazione sarebbe stata apportata di nuovo, ma l'utilizzo del risultato come B * avrebbe portato rapidamente a problemi.

3

Nel caso 1, il confronto esegue automaticamente il puntatore C su un puntatore B. In questo caso, ciò significa che l'indirizzo effettivo cambia, poiché si utilizza l'ereditarietà multipla e B è il secondo nell'elenco di classi base. Per essere più specifici, il puntatore deve essere compensato da (almeno) sizeof (A). Nel secondo caso, tuttavia, non viene eseguita alcuna conversione automatica, quindi il "prefisso A" rende i due puntatori non uguali.

+0

Non esiste un "cast automatico". Un cast è una conversione esplicita, esiste nel codice sorgente. – curiousguy

+0

Cosa intendi con questo? Chiaramente c'è un upcast nel caso 1, ma non è esplicito. – ltjax

+0

Un cast che non è esplicito non è semplicemente un cast. Un cast può essere in stile C, in stile funzionale o in un nuovo stile: '(T) x',' T (x) ',' statico_cast (x) '... – curiousguy