2011-10-10 13 views

risposta

61

Questo non è possibile, e questo è by design. I riferimenti non possono essere rimbalzi.

+0

Nel codice seguente, sto cambiando il riferimento di x a k e sto ancora ottenendo il risultato. Puoi dirmi come è possibile? int a = 50; int &x=a; int k = 10; cout << x << endl; x = k; cout << x << endl; – Rajesh

+1

Non stai cambiando il riferimento, stai assegnando il valore di 'k' all'oggetto a cui si riferisce' x'. Dopo questo compito, 'a == k', e' x' si riferisce ancora a 'a'. –

7

Non è possibile riassegnare un riferimento.

16

Non è possibile riassegnare un riferimento, ma se si sta cercando qualcosa che fornirebbe capacità simili a questo, si può invece fare un puntatore.

int a = 2; 
int b = 4; 
int* ptr = &a; //ptr points to memory location of a. 
ptr = &b;  //ptr points to memory location of b now. 

È possibile ottenere o impostare il valore all'interno del puntatore con:  

*ptr = 5;  //set 
int c = *ptr; //get 
+3

Stai redecando 'ptr'. –

7

Questo non è possibile nel modo desiderato. C++ non ti permette di ricollegare ciò a cui fa riferimento un riferimento.

Tuttavia, se si desidera utilizzare l'inganno si può quasi simulare con un nuovo ambito (MAI fare questo in un programma vero e proprio):

int a = 2; 
int b = 4; 
int &ref = a; 

{ 
    int& ref = b; // Shadows the original ref so everything inside this { } refers to `ref` as `b` now. 
} 
+4

quasi -1 degno – ThomasMcLeod

48

Con C++ 11 c'è il nuovo (ish) std::reference_wrapper.

#include <functional> 

int main() { 
    int a = 2; 
    int b = 4; 
    auto ref = std::ref(a); 
    //std::reference_wrapper<int> ref = std::ref(a); <- Or with the type specified 
    ref = std::ref(b); 
} 

Questo è anche utile per la memorizzazione di riferimenti in contenitori.

0

Anche se la sua è una cattiva idea in quanto contrasta con l'obiettivo di utilizzare riferimenti, è possibile modificare il riferimento direttamente

const_cast< int& >(ref)=b; 
+7

È divertente come le persone fanno +1 alla soluzione sbagliata. Questo codice cambierà la variabile in cui i punti di riferimento non si riferiscono allo stesso – Slava

+0

Nulla mi sorprende più sui siti di Exchange: D – GameDeveloper

+0

Ehi, questa è chiaramente una risposta sbagliata. @visu, per favore rimuovilo. – einpoklum

3

Si può fare un involucro di riferimento molto semplice utilizzando la nuova collocazione:

template< class T > 
class RefWrapper 
{ 
public: 
    RefWrapper(T& v) : m_v(v){} 

    operator T&(){ return m_v; } 
    T& operator=(const T& a){ m_v = a; return m_v;} 
    //...... // 
    void remap(T& v) 
    { 
     //re-map reference 
     new (this) RefWrapper(v); 
    } 

private: 
    T& m_v; 
}; 


int32 a = 0; 
int32 b = 0; 
RefWrapper<int> r(a); 

r = 1; // a = 1 now 
r.remap(b); 
r = 2; // b = 2 now 
+2

Questa risposta è molto più complicata del necessario: la domanda era molto semplice e si poteva rispondere con un solo liner. – lukelazarovic

3

Questo è possibile. Perché sotto il cappuccio, il riferimento è un puntatore. Il seguente codice stamperà "ciao mondo"

#include "stdlib.h" 
#include "stdio.h" 
#include <string> 

using namespace std; 

class ReferenceChange 
{ 
public: 
    size_t otherVariable; 
    string& ref; 

    ReferenceChange() : ref(*((string*)NULL)) {} 

    void setRef(string& str) { 
     *(&this->otherVariable + 1) = (size_t)&str; 
    } 
}; 

void main() 
{ 
    string a("hello"); 
    string b("world"); 

    ReferenceChange rc; 

    rc.setRef(a); 
    printf("%s ", rc.ref.c_str()); 

    rc.setRef(b); 
    printf("%s\n", rc.ref.c_str()); 
} 
+0

Qualsiasi effetto tu abbia su UB non significa che "funzioni" – Slava

+0

@Slava: è in realtà un comportamento non definito? Un riferimento non definito per essere un "puntatore travestito", per così dire? – einpoklum

+0

'otherVariable' non è richiesto usando' * ((uintptr_t *) this) = ((uintptr_t) & str) 'in' setRef' – joas

4

Formalmente, che è impossibile in quanto è vietato in base alla progettazione. Arbitrariamente parlando, è possibile.

Un riferimento è memorizzato come puntatore, in modo da poter sempre cambiare dove punta fino a quando si sa come ottenere il suo indirizzo. Allo stesso modo, puoi anche cambiare il valore delle variabili const, delle variabili membro const o anche delle variabili membro private quando non hai accesso.

Ad esempio, il seguente codice di riferimento è cambiato const membro privato della classe di A: uscita

#include <iostream> 
using namespace std; 

class A{ 
private: 
    const int &i1; 
public: 
    A(int &a):i1(a){} 
    int geti(){return i1;} 
    int *getip(){return (int*)&i1;} 
}; 

int main(int argc, char *argv[]){ 
    int i=5, j=10; 
    A a(i); 
    cout << "before change:" << endl; 
    cout << "&a.i1=" << a.getip() << " &i=" << &i << " &j="<< &j << endl; 
    cout << "i=" << i << " j=" <<j<< " a.i1=" << a.geti() << endl; 
    i=6; cout << "setting i to 6" << endl; 
    cout << "i=" << i << " j=" <<j<< " a.i1=" << a.geti() << endl; 

    *(int**)&a = &j; // the key step that changes A's member reference 

    cout << endl << "after change:" << endl; 
    cout << "&a.i1=" << a.getip() << " &i=" << &i << " &j="<< &j << endl; 
    cout << "i=" << i << " j=" <<j<< " a.i1=" << a.geti() << endl; 
    j=11; cout << "setting j to 11" << endl; 
    cout << "i=" << i << " j=" <<j<< " a.i1=" << a.geti() << endl; 
    return 0; 
} 

Programma:

before change: 
&a.i1=0x7fff1b624140 &i=0x7fff1b624140 &j=0x7fff1b624150 
i=5 j=10 a.i1=5 
setting i to 6 
i=6 j=10 a.i1=6 

after change: 
&a.i1=0x7fff1b624150 &i=0x7fff1b624140 &j=0x7fff1b624150 
i=6 j=10 a.i1=10 
setting j to 11 
i=6 j=11 a.i1=11 

Come si può vedere che a.i1 inizialmente punta a i, dopo la modifica, punta a j.

Tuttavia, fare questo è considerato pericoloso e quindi non raccomandato, in quanto sconfigge lo scopo originale di incapsulamento dei dati e OOP. È più come l'hacking degli indirizzi di memoria.

Problemi correlati