2013-03-21 16 views
5

So che posso ottenere un puntatore a membro di dati per una classe o struct, ma l'ultima riga del seguente codice fallisce la compilazione:Converti in membro di dati a void *

struct abc 
{ 
    int a; 
    int b; 
    char c; 
}; 

int main() 
{ 
    typedef struct abc abc; 
    char abc::*ptt1 = &abc::c; 
    void *another_ptr = (void*)ptt1; 
} 

perché non posso farlo Converto ptt1 in another_ptr? Stiamo parlando di puntatori così un puntatore dovrebbe avere una dimensione simile a un altro (anche se concettualmente diverso)

+0

Qual è il messaggio di errore? –

+1

"typedef struct abc abc;" Veramente? –

+0

Sto utilizzando MSVC2012: errore C2440: 'tipo cast': impossibile convertire da 'char abc :: *' a 'void *' – Paul

risposta

9

Un puntatore al tipo di membro della classe non statica non è lo stesso di un oggetto tipo puntatore; si comportano in modo molto diverso. In effetti, non puoi nemmeno dereferenziare un puntatore al membro con *. Per accedere a un membro tramite un puntatore al membro, si utilizzano invece gli operatori .* e ->*. Se lo è possibile eseguire il cast in un puntatore a oggetti come in questo caso, cosa succederebbe, quindi, se lo avessi consultato con *?

unico oggetto tipi di puntatore hanno una conversione standard per void* (§4.10):

Un prvalue di tipo "puntatore a cvT", dove T è un tipo di oggetto, può essere convertito in un prvalue di tipo "puntatore a cvvoid".

Sono così diversi che la norma va anche al di fuori del suo modo per assicurarsi che il termine "puntatore" non include i puntatori a membri non statici (§3.9.2):

Fatta eccezione per i puntatori ai membri statici, il testo che si riferisce a "puntatori" non si applica ai puntatori ai membri.

+0

L'unica cosa che puoi fare con un 'void *' è di ricollocarlo all'originale digitare comunque, quindi la domanda di possibile utilizzo non è necessariamente valida. Non puoi nemmeno dereferenziare un 'void *' con '*'. –

+0

@JamesKanze Ha rifondato per rendere più chiaro il punto. –

+0

Tranne che non è ancora chiaro cosa intendi per "normali puntatori". Solo i puntatori agli oggetti (nel senso C++) possono essere convertiti in 'void *'. I puntatori ai membri e i puntatori alle funzioni non possono. –

0

Stai cercando di fare qualcosa del genere?

struct ABC 
{ 
    int a; 
    int b; 
    char c; 
}; 

int main() 
{ 
    ABC abc; 
    char *ptt1 = &abc.c; 
    void *another_ptr = (void*)ptt1; 
} 
+0

Sì ma senza oggetto – Paul

+0

Senza un oggetto non ha senso, però. – Damon

+1

Ecco un'analogia orribilmente tesa: quello che hai tentato è come cercare di sbattere un chiodo nel progetto di una casa anziché nella casa stessa. –

2

La ragione principale è perché non v'è alcun requisito che un puntatore al membro hanno la stessa dimensione e rappresentazione come un puntatore a dati. In pratica, è difficile immaginare un puntatore a un membro di dati che non può essere inserito in un void*, poiché un puntatore a un membro dati deve solo contenere uno scostamento . In parole povere, un puntatore a un membro di dati sarà mai più grande di uno size_t e un void* deve essere di dimensioni almeno pari a size_t. D'altra parte, potrebbe contenere facilmente modelli di bit che non erano legali in un puntatore. Infatti, come sottolinea Steve Jessop, i puntatori ai membri richiedono informazioni aggiuntive, poiché se il membro si trova in una base virtuale, il suo offset dipende dalla classe più derivata e deve essere calcolato dinamicamente, in base a informazioni aggiuntive nel puntatore.

Più in generale, un void* può contenere solo un puntatore ai dati. Deve essere grande come il più grande indicatore di dati (in genere un char*), ma i puntatori a funzioni, e puntatori membri, può essere più grande, e non in forma (e puntatore a funzioni membro quasi mai andare bene).

+0

"un puntatore a un membro dati ha solo bisogno di contenere un offset" - a meno che il membro non sia in una classe base virtuale, nel qual caso è necessario altro (credo. Sto sbagliando, è solo con puntatore a membro -funzione che sia difficile?). –

+0

@SteveJessop Hai ragione. Non so dove l'ho visto presentato come un offset semplice. Con VC 2012, modalità a 32 bit, 'int *' ha una dimensione di 4, 'int Class :: *' 12. (Vieni a pensarci, penso che l'ultima volta che l'ho guardato in dettaglio era prima l'ereditarietà multipla è stata aggiunta alla lingua e l'unica difficoltà è rappresentata dalle funzioni virtuali.) –