2011-01-16 15 views
8

Nello snippet di codice, sono in grado di accedere alla variabile membro privata al di fuori dell'ambito della classe. Anche se questo non dovrebbe mai essere fatto, perché è permesso in questo caso? È una cattiva pratica ricevere una variabile privata restituita per riferimento?Perché è possibile esporre membri privati ​​quando restituisco un riferimento da una funzione membro pubblico?

#include <iostream> 
#include <cstdlib> 

class foo 
{ 
    int x; 
    public: 
     foo(int a):x(a){} 
     int methodOne() { return x; } 
     int& methodTwo() { return x; } 
}; 

int main() 
{ 
    foo obj(10); 
    int& x = obj.methodTwo(); 
    x = 20;    // With this statement, modifying the state of obj::x 

    std::cout << obj.methodOne(); 
    getchar(); 
    return 0; 
} 

E per quanto riguarda questo metodo, cosa comunica il tipo di reso? E anche quando dovrei avere un tipo di ritorno di questo tipo?

int& methodTwo() { return x; } 

PS: Mi dispiace se l'oggetto è vago. Qualcuno può cambiarlo con il contenuto rilevante qui. Grazie.

risposta

15

private non significa "questa memoria può essere modificata solo dalle funzioni membro" - significa "i tentativi diretti di accedere a questa variabile provocheranno un errore di compilazione". Quando esponi un riferimento all'oggetto, hai effettivamente esposto l'oggetto.

È una cattiva pratica ricevere una variabile privata restituita per riferimento?

No, dipende da ciò che si desidera. Cose come std::vector<t>::operator[] sarebbero piuttosto difficili da implementare se non fossero in grado di restituire un riferimento non const :) Se si desidera restituire un riferimento e non si desidera che i client siano in grado di modificarlo, è sufficiente impostarlo come riferimento const.

+0

Per le persone che passano: [questa domanda] (http://stackoverflow.com/questions/8005514/is-returning-references-of-member-variables-bad-pratice) suggerisce che può essere pericoloso restituire un riferimento al membri della classe. – Arthur

+0

@Arthur: Sì, come ho detto, dipende da cosa vuoi fare. Funziona bene per 'std :: vector' - ma ci sono molti casi in cui è anche la cosa sbagliata. –

3

La restituzione di membri privati ​​come riferimento è perfettamente valida e il programmatore che scrive una classe è responsabile di scegliere attentamente se ciò deve essere consentito. This link fornisce un esempio quando questo può essere fatto.

2

Questo codice:

int& methodTwo() { return x; } 

significa che la funzione restituisce un riferimento ad un numero intero. Proprio come quando si passa un valore in base a una funzione, se viene modificato il valore di ritorno di methodTwo, viene restituito anche il valore methodTwo. In questo caso, campo classe x.

Nel codice che hai scritto, questo significa che stai permettendo alla variabile privata x di uscire dall'ambito (un campo classe) e di essere passata nel mondo esterno. Questa è certamente una cattiva pratica (perché x può essere cambiato in modi che possono rompere classe foo, ma è certamente ammissibile.

Ricordate pubblico/privato/protette sono compile-time solo. Una volta che l'applicazione viene compilato, campi privati ​​siedono accanto ai campi pubblici e non c'è protezione contro le modifiche, lo stesso vale per i linguaggi gestiti come C# e Java

Generalmente si dovrebbe evitare di restituire riferimenti perché rende difficile la comprensione di costruttori/distruttori chiamata, tuttavia, restituire un riferimento può essere più veloce. Se il metodo ha restituito un tipo di struct che era ENORME, restituendo un riferimento const a quello stesso il tipo di canale dovrebbe prendere solo da quattro a otto byte (un puntatore a quell'oggetto). Tuttavia, ci sono modi migliori per ottimizzare questo tipo di cose.

+1

Sono fortemente fortemente in disaccordo sul punto "dovresti evitare di ritornare i riferimenti" - dato che il compilatore è libero di elidere le chiamate al costruttore di copie se si restituisce per valore, l'unica cosa che si ottiene in molti casi ritornando da valore è build debug lenta (perché il compilatore fa RVO/NRVO su di te in modalità di rilascio). –

+1

Non essendo un utente C++ di livello guru, mi riservo il diritto di sbagliare :) Ma non si otterrà un comportamento indefinito se si restituisce un riferimento a una variabile locale? (Ad esempio, si rimane con un puntatore a qualche punto casuale nello stack?) –

+0

Questo è corretto. Il tentativo di accedere a una variabile distrutta tramite riferimento produce un comportamento non definito. Ma per cose come i getter di classe che ritornano per riferimento è un comportamento normale e atteso. –

0

Come ha detto Donotalo, è perfettamente valido.L'idea di avere membri privati ​​è di disabilitare altre classi/funzioni per accedere al membro privato della classe senza la tua autorizzazione. Se siete felici di fare una funzione per permettere ad altre classi/funzioni per accedere ai soci privati, il compilatore ha nulla contro che in realtà :-)

Di solito, è utile avere un membro privato e hanno un ottenere funzione per consentire ad altre classi/funzioni di ottenere il valore della funzione, ma solo la classe sarà in grado di cambiarla.

-1

sono in grado di accedere alla variabile membro privato al di fuori della portata della classe

Se lei si riferisce alla x in main() allora che è diversa da quella dichiarata in xclass foo. Se provi ad accedere allo obj.x, il compilatore si lamenterà sicuramente.

È una cattiva pratica ricevere una variabile privata restituita per riferimento?

Non c'è niente di sbagliato nel "ricevere" il riferimento a un membro privato. Ma dare il riferimento a un membro privato rende la dichiarazione privata inutile. Dichiarando una variabile come membro privato, si limita l'accesso a tale membro solo ai metodi della classe.

per quanto riguarda questo metodo, cosa comunica il tipo di reso? E anche quando dovrei avere un tipo di ritorno di questo tipo?

Non sei sicuro del metodo a cui ti riferisci?!?!?!

+2

Davvero? Lo rende inutile? Come si spiega 'std :: vector :: operator []' allora? Qualunque puntatore del buffer utilizzato dal vettore non è esposto al mondo, ma i dati sono (e dovrebbero essere, dato il punto del vettore) –

+0

@Billy O'Neal: buon punto. Grazie per segnalarlo. – yasouser

Problemi correlati