2011-10-10 15 views

Respuesta

61

Esto no es posible, y eso es by design. Las referencias no pueden ser rebotadas.

+0

En el siguiente código, estoy cambiando la referencia de x a k y sigo obteniendo el resultado. ¿Puedes decirme cómo es esto posible? int a = 50; int &x=a; int k = 10; cout << x << endl; x = k; cout << x << endl; – Rajesh

+1

No está cambiando la referencia, está asignando el valor de 'k' al objeto al que hace referencia' x'. Después de esta asignación, 'a == k', y' x' todavía se refiere a 'a'. –

7

No puede reasignar una referencia.

16

No puede reasignar una referencia, pero si está buscando algo que le proporcione capacidades similares, puede hacer un puntero en su lugar.

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. 

Puede obtener o establecer el valor dentro del puntero con:  

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

Estás redeclarando 'ptr'. –

7

Eso no es posible en la forma que desee. C++ simplemente no te permite volver a vincular a lo que apunta una referencia.

Sin embargo, si desea utilizar el engaño casi se puede simular con un nuevo campo de aplicación ( NUNCA hacer esto en un programa real):

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

casi -1 digno – ThomasMcLeod

48

con C++ 11 está el nuevo (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); 
} 

Esto también es útil para almacenar referencias en contenedores.

0

A pesar de su mala idea, ya que contradice el objetivo de la utilización de referencias, es posible cambiar la referencia directa

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

Es curioso cómo las personas +1 solución equivocada. Este código cambiará la variable a la que hace referencia el punto de referencia, no se refiere a sí mismo – Slava

+0

Ya no me sorprende en los sitios de Exchange: D – GameDeveloper

+0

Oye, esta es claramente una respuesta incorrecta. @visu, por favor quítalo. – einpoklum

3

Se puede hacer una envoltura de referencia muy fácil usando la colocación de nuevo:

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

Esta respuesta es mucho más complicada de lo necesario; la pregunta era muy simple y podía responderse con un solo mensaje. – lukelazarovic

3

Esto es posible. Porque debajo del capó, la referencia es un puntero. El código siguiente imprimirá "hola mundo"

#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

Cualquier efecto que tengas en UB no significa que "funciona" – Slava

+0

@Slava: ¿Es realmente un comportamiento indefinido? ¿Es una referencia no definida como un "puntero disfrazado", por así decirlo? – einpoklum

+0

'otherVariable' no es requerido usando' * ((uintptr_t *) this) = ((uintptr_t) & str) 'en' setRef' – joas

4

Formalmente hablando, eso es imposible, ya que está prohibido por diseño. Arbitrariamente hablando, eso es posible.

Las referencias se almacenan como un puntero, por lo que siempre puede cambiar a dónde apunta siempre y cuando sepa cómo obtener su dirección. Del mismo modo, también puede cambiar el valor de las variables de const, las variables de miembros de const o incluso las variables de miembros privados cuando no tiene acceso.

Por ejemplo, el siguiente código de referencia ha cambiado const miembro privado de la clase A: salida

#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; 
} 

Programa:

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 

Como se puede ver que un .i1 apunta inicialmente a i, después del cambio, apunta a j.

Sin embargo, hacerlo es considerado como peligroso y, por lo tanto, no recomendado, ya que anula el objetivo original de encapsulación de datos y OOP. Es más parecido a la piratería de direcciones de memoria.

Cuestiones relacionadas