2012-02-29 3 views
17

Ho deciso di verificare se assegnare un riferimento a un membro renderebbe un membro un riferimento. Ho scritto il seguente frammento per testarlo. Esiste una classe semplice Wrapper con un std::string come variabile membro. Prendo uno const string& nel costruttore e lo assegno alla variabile membro pubblico. Più tardi nel metodo main() modifico la variabile membro ma il string passato al costruttore rimane invariato, come mai? Penso che in Java la variabile sarebbe cambiata, perché non in questo frammento di codice? Come funzionano esattamente le referenze in questo caso?Passaggio tramite riferimento a un costruttore

#include <iostream> 
#include <string> 
using namespace std; 

class Wrapper 
{ 
public: 
    string str; 

    Wrapper(const string& newStr) 
    { 
     str = newStr; 
    } 
}; 

int main (int argc, char * const argv[]) 
{ 
    string str = "hello"; 
    cout << str << endl; 
    Wrapper wrapper(str); 
    wrapper.str[0] = 'j'; // should change 'hello' to 'jello' 
    cout << str << endl; 
} 
+2

I tipi in C++ sono ciò che decreta e non diventano magicamente altro. Tu dici 'stringa' e ottieni una' stringa'. Se volessi un riferimento, avresti detto 'stringa &'. –

+0

Hai abusato di persone con una domanda troppo semplice :) – Mikhail

+2

In Java la variabile non sarebbe stata modificata perché il codice non sarebbe stato compilato; le stringhe in Java non possono essere modificate. –

risposta

22

Per assegnare un riferimento in un costruttore è necessario disporre di un membro di riferimento

class A{ 
    std::string& str; 
public: 
    A(std::string& str_) 
    : str(str_) {} 
}; 

str ora è un riferimento al valore passato in. Lo stesso vale per arbitri const

class A{ 
    const std::string& str; 
public: 
    A(const std::string& str_) 
    : str(str_) {} 
}; 

Tuttavia non dimenticare che una volta che un riferimento è stato assegnato, non può essere modificato, quindi se l'assegnazione richiede una modifica a str, allora dovrà essere un puntatore.

5

Poiché Wrapper::str non è un riferimento, è un oggetto indipendente. Quindi, quando fai il numero str = newStr, sei copiando la stringa.

1

È necessario dichiarare Wrapper::str come string&, non come string.

3

è necessario utilizzare un inizializzatore e dichiarare str come riferimento come in:

class Wrapper { 
public: 
    string &str; 

    Wrapper(string& newStr) 
     : str(newStr) { 
    } 
}; 

Il modo in cui si sta scrivendo, tutto quello che stai facendo è copiando il valore del riferimento si passa alla constuctor . Non stai salvando il riferimento. Dichiarando un riferimento come membro della classe e inizializzandolo con un riferimento a un'altra istanza di stringa, si otterrà il comportamento che si sta cercando.

+1

Il codice tenta di inizializzare un riferimento-mutabile con un riferimento-a-const. –

+0

Risolto ... è quello che ottengo per copiare ciecamente dall'OP. – andand

5
class Wrapper 
{ 
public: 
    string& str; 

    Wrapper(string& newStr) : str(newStr) {} 
}; 

Nota, non è possibile accettare un const string& e conservarlo in un string&, si perderebbe const correttezza nel farlo.

1

La variabile del corpo principale è std::string.

La variabile parametro è const std::string&.

I riferimenti const in sono sempre "const di basso livello", ovvero modificano il tipo di oggetto non l'oggetto reale.

Al contrario un "primo livello const" modifica un oggetto reale. Leggi C++ Primer on Top level const per chiarimenti.

Ecco come la vostra assegnazione appare come quando si passa argomenti:

const std::string& = std::str; //Values are ommited 
// i.e const std::string newStr = std::string str 

Stai inizializzazione di un const type reference con un non-const value che è accettabile. Non è necessario modificare il valore di std::string str utilizzando tale riferimento.E, se provi a cambiare il valore di newStr all'interno del costruttore, si ottiene un errore di compilazione.

successivo che stai facendo un altro incarico all'interno del costruttore che è anche accettabile:

std::string = const std::string 

Il fatto che wrap.str[0] non cambiava str di main è che, anche se un riferimento è stato utilizzato per creare un'istanza class str, class str ha il suo oggetto e non è collegato a main str. L'utilizzo di tale riferimento in un parametro collega semplicemente tale parametro a main str; non main str a class str.

Se le variabili di classe sono state referenziate, potrebbe essere cambiato.