2011-12-03 5 views
6

Ho trovato uno strano comportamento durante l'utilizzo di una variabile di riferimento.Variabile di riferimento e funzioni virtuali

Ecco implementazioni di classe:

class Base { 
    public: 
     virtual void Method() = 0; 
}; 

class DerivedA : public Base { 
    public: 
     virtual void Method() {} 
} 

class DerivedB : public Base { 
    public: 
     virtual void Method() {} 
} 

Ecco un codice di esempio che ha il comportamento anomalo:

void main(int argc, char *argv[]) { 
    DerivedA a; 
    DerivedB b; 
    Base &base = a; 

    base.Method(); // Calls DerivedA::Method 

    base = b; 
    base.Method(); // Calls DerivedA::Method!!! Why doesn't call DerivedB.Method()? 
} 

In conclusione, sembra che la funzione virtuale tavolo pointer "associato" al la variabile di riferimento viene determinata solo quando si inizializza la variabile di riferimento. Se riassegno la variabile di riferimento, lo vfpt non cambia.

Cosa succede qui?

risposta

13

Base &base è un riferimento, cioè alias all'oggetto a, quindi l'assegnazione base = b è equivalente a a = b, che lascia il base thingie ancora lo stesso oggetto della stessa classe. Non è una riassegnazione del puntatore come sembri assumere.

+5

Penso che questa risposta merita il segno di spunta verde! – Walter

+2

Sì, penso che questa dovrebbe essere la risposta accettata. – Rafid

+0

Grazie, anche se la risposta accettata è accettata dall'interrogante e va bene che abbia accettato l'altra risposta ;-) –

7

I riferimenti possono essere inizializzati solo una volta. Non è possibile assegnare un nuovo oggetto a un riferimento. Quello che sta realmente accadendo qui è che viene chiamato operator = di Base e l'oggetto sottostante è ancora DerivedA e non DerivedB.

+2

Ogni giorno c'è sempre qualcosa da imparare. – Luca

+0

Non sono sicuro che sia corretto in realtà. L'operatore = non è definito in Base, quindi non c'è nulla da chiamare in realtà, a parte l'implementazione predefinita in C++ dell'operatore =. Penso che quello che sta accadendo qui è ciò che @MichaelKrelin ha risposto di seguito. – Rafid

+0

@Rafid Come hai scritto, c'è l'implementazione predefinita di operator =. L'implementazione predefinita non è virtuale e il tipo di base è Base, quindi viene chiamato Base :: operator =(). Anche la risposta di Michael è corretta. Le due risposte non si contraddicono a vicenda. – selalerer