Dove sono archiviate le funzioni membro per un object?

Sto sperimentando con C ++ per capire come class / strutture e i loro rispettivi oggetti sono disposti in memoria e ho capito che ogni campo di una class / struttura è un offset nel loro rispettivo object (quindi posso avere un puntatore variabile membro).

Non capisco perché, anche se posso avere dei puntatori funzione membro, il seguente codice non funziona:

struct mystruct { void function() { cout <c); unsigned int offset_from_start_structure2 = (unsigned int)(&((mystruct*)0)->function); // ERROR - error C2276: '&' : illegal operation on bound member function expression return 0; } 

La mia domanda è: perché la linea

 unsigned int offset_from_start_structure = (unsigned int)(&((mystruct*)0)->c); 

compilare e restituire l’offset del campo “c” dall’inizio della struttura e della linea

 unsigned int offset_from_start_structure2 = (unsigned int)(&((mystruct*)0)->function); 

non si compila nemmeno?

    Le funzioni membro o puntatori ad esse non vengono memorizzate nell’object. (Le funzioni virtual vengono in genere chiamate attraverso un puntatore memorizzato in una tabella a cui un object ha un singolo puntatore). Questo sarebbe un enorme spreco di memoria. Solitamente sono memorizzati in una sezione di memoria di codice e sono noti al compilatore. L’object ( *this ) viene generalmente passato come un parametro invisibile in modo che le funzioni sappiano su quale object operare quando vengono chiamate.

    Quindi, in parole povere, avresti

      0x10001000 void A::foo .......... {code for A::foo} 

    e

      push a; call A::foo (0x10001000) pop a; 

    dove a è l’object su cui stai chiamando.

    In pratica, gli indicatori di funzione degli utenti non sono memorizzati negli oggetti: non è necessario. Lo standard C ++ non specifica esattamente come devono essere implementate le funzioni virtuali, ma la pratica comune per le funzioni dei membri virtuali è che ogni object contiene un puntatore a una tabella di puntatori di funzione; questo puntatore è chiamato puntatore vtable .

    Potresti provare ad entrare in possesso di “Inside the C ++ object model” di Stanley Lippman.

    Oppure, potresti semplicemente provare ad afferrare il mio vecchio tutorial sui puntatori , che una volta faceva riferimento all’articolo di puntatori di Wikipedia, prima che il mio sito di homepage scomparisse.


    Per quanto riguarda la seconda domanda, perché prendere l’indirizzo di p->memberFunc fa sì che il compilatore p->memberFunc un po ‘, beh quell’espressione non ha tipo, è solo un’ quadro sintattica , alla quale è ansible applicare una lista di argomenti per chiamare la funzione.

    A proposito,

     struct S { void foo() {} }; #include  #include  using namespace std; int main() { S* p = 0; typeid( &p->foo ); } 

    Compilazione:

     [W: \ dev \ test]
     > g ++ foo.cpp
     foo.cpp: nella funzione 'int main ()':
     foo.cpp: 12: 17: errore: ISO C ++ proibisce di prendere l'indirizzo di una funzione membro legata per formare un puntatore alla funzione membro.  Dì "& S :: foo" [-fpermissive]
     foo.cpp: 12: 22: warning: il valore calcolato non viene utilizzato [-Wunused-value]
     foo.cpp: 12: 22: warning: l'istruzione non ha alcun effetto [-Wunused-value]
    
     [W: \ dev \ test]
     > _