2011-10-10 14 views

Odpowiedz

61

To nie jest możliwe, a to by design. Odniesienia nie mogą być odbiciem.

+0

W kodzie poniżej zmieniam odniesienie x do k i nadal otrzymuję wynik. Czy możesz mi powiedzieć, jak to jest możliwe? int a = 50; int &x=a; int k = 10; cout << x << endl; x = k; cout << x << endl; – Rajesh

+1

Nie zmieniasz odniesienia, przypisujesz wartość 'k' do obiektu, do którego odnosi się' x'. Po tym przypisaniu, 'a == k' i' x' nadal odnosi się do 'a'. –

7

Nie można ponownie przypisać odniesienia.

16

Nie można ponownie przypisać odniesienia, ale jeśli szukasz czegoś, co zapewnia podobne możliwości, możesz zamiast tego użyć wskaźnika.

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. 

można uzyskać lub ustawić wartość wskaźnika z wewnątrz:  

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

Jesteś redeclaring 'ptr'. –

7

nie jest to możliwe w sposób chcesz. C++ po prostu nie pozwala ci powtórzyć tego, na co wskazuje punkt odniesienia.

Jednak jeśli chcesz używać sztuczek można prawie zasymulować z nowym zakresem (NIGDY to zrobić w prawdziwym programu):

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

prawie -1 godny – ThomasMcLeod

48

z C++ 11 nie jest nowy (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); 
} 

Jest to również przydatne do przechowywania referencji w pojemnikach.

0

Chociaż jest to zły pomysł, gdyż celowość stosowania odniesień, jest możliwe, aby zmienić odniesienie bezpośrednio

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

To zabawne, jak ludzie dają +1 złe rozwiązanie. Ten kod zmieni zmienną, gdzie ref wskazuje, a nie samą referencję. – Slava

+0

Nic już mnie nie zaskakuje na stronach Exchange: D – GameDeveloper

+0

Hej, to jest oczywiście zła odpowiedź. @visu, usuń go. – einpoklum

3

można dokonać wrapper odniesienie bardzo łatwe przy użyciu umieszczenie nowego:

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

Ta odpowiedź jest o wiele bardziej skomplikowana, niż jest to konieczne - pytanie było bardzo proste i można było odpowiedzieć jednym linerem. – lukelazarovic

3

Jest to możliwe. Ponieważ pod maską odniesienie jest wskaźnikiem. Poniższy kod wypisze „hello world”

#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

Niezależnie od tego, jaki masz wpływ na UB, nie oznacza to, że "działa". – Slava

+0

@Slava: Czy to w rzeczywistości niezdefiniowane zachowanie? Czy odniesienie nie jest zdefiniowane jako "wskaźnik w przebraniu", że tak powiem? – einpoklum

+0

'otherVariable' nie jest wymagany przy użyciu' * ((uintptr_t * this this) = ((uintptr_t) & str) 'in' setRef' – joas

4

Formalnie rzecz biorąc, jest to niemożliwe, ponieważ jest to zabronione przez projekt. Mówiąc arbitralnie, jest to możliwe.

Odwołania są zapisywane jako wskaźniki, więc zawsze można zmienić ich położenie, o ile wiadomo, jak uzyskać jego adres. Podobnie możesz zmienić wartość zmiennych stałych, zmiennych składowych stałych, a nawet zmiennych prywatnych, gdy nie masz do nich dostępu.

Na przykład, następujący kod zmieniła Klasa A jest const prywatną odniesienie użytkownika: wyjście

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

Program:

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 

Jak widać że a.i1 początkowo wskazuje na i, po zmianie wskazuje na j.

Jednak jest to uważane za niebezpieczne, a zatem niezalecane, ponieważ pokonuje pierwotny cel enkapsulacji danych i OOP. To bardziej przypomina hackowanie adresów pamięci.

Powiązane problemy