2016-06-21 14 views
7

Ho letto un esempio su polimorfismo che assomiglia a soffietto, dove show() è una funzione virtuale:Perché non utilizzare l'associazione anticipata quando possibile?

int main() 
{ 
    Derived dv1; 
    Derived dv2; 
    Base* ptr; 

    ptr = &dv1; 
    ptr->show(); 

    ptr = &dv2; 
    ptr->show(); 
} 

I libri dicono che in questo caso, il compilatore utilizzerà late binding tecnica. Comprendo la differenza tra l'associazione tardiva e l'associazione anticipata. Tuttavia, in questo esempio, noi (e forse anche il compilatore) possiamo vedere quale funzione dovrebbe essere chiamata perché non c'è alcun cambiamento negli oggetti a cui punta ptr. Quindi, perché non legare in anticipo in questo caso perché l'associazione tardiva causerà un sovraccarico?

+4

Come sai che il tuo compilatore in realtà non rileva quel caso e fa qualche ottimizzazione per questo? Hai controllato il codice assembler generato? Con le ottimizzazioni abilitate? –

+0

Non ho familiarità con il codice assembler. Il fatto che i libri dicano che il legame tardivo è applicato in questo caso mi rende confuso. – Rickie

+2

clang sembra almeno fare [a * bit * more] (https://godbolt.org/g/9pnkg9) piuttosto che ottimizzare le chiamate da derivare, almeno per le semplici implementazioni di 'show'. – jaggedSpire

risposta

8

Tuttavia, in questo esempio, noi (e forse anche il compilatore) possiamo vedere quale funzione deve essere chiamata perché non vi è alcun cambiamento negli oggetti a cui ptr punta.

Corretto.

Quindi, perché non impegnarsi presto in questo caso perché l'associazione tardiva causerà un sovraccarico?

La funzione viene chiamata tramite un puntatore a un tipo polimorfico, quindi viene utilizzato il binding tardivo.

L'associazione tardiva significa semplicemente che la chiamata verrà risolta sull'override più derivata (fino al tipo concreto dell'oggetto), anziché sulla chiamata allo Base::show.

Certo, la spedizione dinamica può essere necessaria per l'associazione tardiva in generale, ma l'implementazione può infrangere le regole, se il programma si comporta ancora come se avesse seguito le regole. Questa è conosciuta come la regola as-if. E a causa dell'osservazione che hai fatto anche tu, cambiare il programma per fare il dispatch statico non cambia il comportamento, quindi al compilatore è permesso di ottimizzare ed evitare di fare dispatch dinamico.

+1

Questa tecnica è chiamata _devirtualization_. Puoi leggere l'implementazione di GCC in [serie di post del blog] (http://hubicka.blogspot.ru/2014/01/devirtualization-in-c-part-1.html) –

Problemi correlati