Compilazione statica e classi derivate

di il
5 risposte

Compilazione statica e classi derivate

Dato questo frammento di codice che ho trovato in rete: 

#include <iostream>
using namespace std;

struct A {
   void f() { cout << "Class A" << endl; }
};

struct B: A {
   void f() { cout << "Class B" << endl; }
};

void g(A& arg) {
   arg.f();
}

int main() {
   B x;
   g(x);
}

il testo dice: 

quando viene richiamata la funzione g() , viene richiamata la funzione A::f() , anche se l'argomento fa riferimento a un oggetto di tipo B

Al momento della compilazione, il compilatore sa solo che l'argomento della funzione g() sarà un riferimento a un oggetto derivato da A;

Domanda: il compilatore perchè non si accorge che l'argomento x passato a g() è di tipo B ?

Lo ignora questo aspetto ?

Grazie

5 Risposte

  • Re: Compilazione statica e classi derivate

    Se osservi il codice assembly comprendi che x viene passata per indirizzo (nel registro rcx con l'opcode lea

    	B x;
    	g(x);
    00007FF724BA247E  lea         rcx,[x]  
    00007FF724BA2482  call        g (07FF724BA10C8h) 

    e poi viene chiamata la funzione g (che sa che il parametro è in rcx).

    Ma l'indirizzo non dice nulla della classe di x e quindi la funzione g non può fare altro che trattarlo come un puntatore alla classe del proprio argomento.

  • Re: Compilazione statica e classi derivate

    Sono un po' arrugginito su queste cose, ma la risposta alla tua domanda va ricercata nel concetto stesso di eredità: 

    Si dice che l'eredità è una relazione di tipo "is a" (un cane è un mammifero, con caratteristiche in più che lo specializzano). Quindi, se due classi, A e B, sono rispettivamente base e derivata, gli oggetti di B sono (anche) oggetti di A, ma non viceversa.

    Ne consegue che le conversioni implicite di tipo da B ad A (cioè da classe derivata a classe base) sono sempre ammesse (con il mantenimento dei soli i membri comuni), e in particolare ogni puntatore (o riferimento) ad A può essere assegnato o inizializzato con l'indirizzo (o il nome) di un oggetto di B. Questo permette, quando si ha a che fare con una gerarchia di classi, di definire all'inizio un puntatore generico alla classe base "capostipite", e di assegnargli in seguito (in base al flusso del programma) l'indirizzo di un oggetto appartenente a una qualunque classe della gerarchia. Ciò è particolarmente efficace quando si utilizzano le "funzioni virtuali"...

  • Re: Compilazione statica e classi derivate

    22/03/2025 - oregon ha scritto:

    Se osservi il codice assembly comprendi che x viene passata per indirizzo (nel registro rcx con l'opcode lea

    	B x;
    	g(x);
    00007FF724BA247E  lea         rcx,[x]  
    00007FF724BA2482  call        g (07FF724BA10C8h) 

    e poi viene chiamata la funzione g (che sa che il parametro è in rcx).

    Ma l'indirizzo non dice nulla della classe di x e quindi la funzione g non può fare altro che trattarlo come un puntatore alla classe del proprio argomento.

    Chiarissimo, Grazie. Ora capisco... si doveva scendere a basso livello 

  • Re: Compilazione statica e classi derivate

    22/03/2025 - zio_mangrovia ha scritto:

    Chiarissimo, Grazie. Ora capisco... si doveva scendere a basso livello 

    In realtà quello che avviene a basso livello, con i vari dettagli implementativi, è una conseguenza del funzionamento generale stabilito a monte dalle regole del linguaggio di programmazione in questione.

  • Re: Compilazione statica e classi derivate

    Basta sapere che tramite reference (o puntatore) ad A accede ai membri di A. Difatti se cancelli f() in A ti da errore sulla chiamata in g() perché non la trova, ma se la cancelli in B non se ne accorge nemmeno.

    Il compilatore può saperlo, ma non ne è tenuto in quando g e main vengono compilate come funzioni a se stanti. Tutto quello che deve controllare è se x è un argomento ammissibile per g. 

Devi accedere o registrarti per scrivere nel forum
5 risposte