2013-02-27 7 views
6

Il paragrafo che segue è stato estratto da pagina 420 da Stroustup libro "The C++ Programming Language" (terza edizione):Penso che la seguente affermazione sia errata o mi manchi qualcosa?

Perché un puntatore a un membro virtuale (s in questo esempio) è una sorta di offset, non dipende dalla posizione di un oggetto in memoria. Un puntatore a un membro virtuale può quindi essere passato in modo sicuro tra spazi di indirizzi diversi a condizione che sia utilizzato lo stesso layout di oggetto in entrambi. Come i puntatori alle funzioni ordinarie, i puntatori alle funzioni membro non virtuali non possono essere scambiati tra spazi di indirizzi.

Sto discutendo l'ultima frase in questo paragrafo. Di seguito, troverai uno snippet di codice in cui i puntatori alle funzioni membro non virtuali foo() e vengono scambiati tra un oggetto di base a e un oggetto derivato b, senza problemi.

Ciò che non può essere fatto è il sovraccarico di una qualsiasi delle funzioni nella base, foo() o foo1(), nella classe derivata, poiché in questo caso il compilatore emetterà un errore come mostrato di seguito.

#include <iostream> 

class A 
{ 
    int i; 
    public: 
    A() : i(1) {} 
    void foo() { std::cout << i << '\n'; } 
    void foo1() { std::cout << 2 * i << '\n'; } 
}; 

class B: public A 
{ 
    int j; 
    public: 
    B() : A(), j(2) {} 
// void foo() { std::cout << j << '\n'; } 
}; 

int main() 
{ 
    typedef void (A::* PMF)(); 
    PMF p = &B::foo; // error C2374: 'p' redefinition, multiple initialization 
         // if foo() is overloaded in B. 
    PMF q = &B::foo1; 
    B b; 
    (b.*p)(); 
    (b.*q)(); 

    A a; 
    (a.*p)(); 
    (a.*q)(); 
} 
+6

La mia lettura di "scambio tra spazi di indirizzi" era qualcosa come una trasmissione diretta di un puntatore a * un altro processo * in un sistema operativo. – ulidtko

risposta

1

Quella frase è corretta: A (standard) C++, un programma, o meglio di processo, ha esattamente uno spazio di indirizzamento. Quindi, come ha sottolineato Ulidtko, questa frase si riferisce alle possibilità di scambiare i puntatori a funzioni membro virtuali vs non virtuali tra spazi di indirizzi di processi diversi.

A non virtuale funzione membro di una classe è praticamente una funzione standard con un argomento implicito l'oggetto si chiama per (l'questo puntatore). Come tale, viene assegnato un certo indirizzo nello spazio degli indirizzi del processo al momento del caricamento. Dove esattamente finisce nello spazio dell'indirizzo dipende certamente dalla tua piattaforma e se questa funzione membro fa parte o meno di una libreria collegata dinamicamente. Il punto è che, per due processi, non è necessariamente lo stesso indirizzo. Quindi passare un puntatore ae quindi eseguire una funzione di questo tipo in un altro processo potrebbe potenzialmente 'impostare la tua macchina in fiamme (TM)'.

Un membro virtuale funzione è ancora praticamente la stessa della funzione di membro non virtuale come in 'qualche indirizzo in memoria di passare a sull'esecuzione e passare il vostro questo puntatore', ma viene chiamato attraverso il tabella delle funzioni virtuali (vtable) anziché direttamente. Quindi un puntatore a una funzione membro virtuale è praticamente solo un indice nella tabella delle funzioni virtuali dell'oggetto. Chiamare quella funzione fa qualcosa sulla falsariga di "prendere il puntatore dell'oggetto, magari incrementare il puntatore per arrivare al vtable dell'oggetto e saltare all'indirizzo dell'indice di quella tabella, passando l'indirizzo dell'oggetto stesso come Puntatore '. Quindi questa indirezione tramite il vtable fa funzionare lo scambio tra il puntatore e la funzione membro virtuale tra gli spazi degli indirizzi.

Disclaimer: Mi sto appoggiando un po 'al mio "so davvero di cosa sto parlando" - zona di comfort qui. Quindi, nel caso in cui abbia semplificato qualcosa o peggio, ancora, impegnato nella distribuzione di informazioni false, mi sento libero di distruggere la mia risposta;).

0

Un puntatore sarà sempre esistere come memoria virtuale, quindi è corretto, è possibile controllare l'indirizzo e vedrete non v'è alcun puntatore fisico per l'indirizzo di memoria

Perché un puntatore a un membro virtuale (s in questo esempio) è un tipo di offset, non dipende dalla posizione di un oggetto in memoria. Un puntatore a un membro virtuale può quindi essere passato in modo sicuro tra diversi spazi di indirizzi, purché lo stesso layout di oggetto sia utilizzato in entrambi. Come i puntatori alle funzioni ordinarie, i puntatori alle funzioni dei membri non virtuali non possono essere scambiati tra gli spazi degli indirizzi.

Problemi correlati