Подтвердить что ты не робот

Как изменить переменную, к которой относится ссылка С++?

Если у меня есть это:

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

Как я могу сделать ref ссылкой на b после этого кода?

4b9b3361

Ответ 1

Это невозможно, и по дизайну. Ссылки не могут быть восстановлены.

Ответ 2

С С++ 11 есть новый (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);
}

Это также полезно для хранения ссылок в контейнерах.

Ответ 3

Вы не можете переназначить ссылку, но если вы ищете что-то, что обеспечит аналогичные возможности, вы можете сделать указатель вместо этого.

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.

Вы можете получить или установить значение внутри указателя с помощью:  

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

Ответ 4

Вы не можете переназначить ссылку.

Ответ 5

Это невозможно по вашему желанию. С++ просто не позволяет вам переустановить, на что ссылается ссылка.

Однако, если вы хотите использовать обман, вы можете почти имитировать его с помощью новой области (НИКОГДА не делайте этого в реальной программе):

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.
}

Ответ 6

Формально говоря, это невозможно, так как это запрещено дизайном. Вообще говоря, это возможно.

Ссылки хранятся в виде указателя, поэтому вы всегда можете изменить, где он указывает, до тех пор, пока вы знаете, как получить его адрес. Аналогичным образом вы также можете изменить значение константных переменных, константных переменных-членов или даже частных переменных-членов, когда у вас нет доступа.

Например, следующий код изменил ссылку на класс A const:

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

Выход программы:

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

Как вы можете видеть, что a.i1 изначально указывает на i, после изменения он указывает на j.

Тем не менее, это считается опасным и, таким образом, не рекомендуется, поскольку оно побеждает исходную цель инкапсуляции данных и ООП. Это больше похоже на взлом памяти.

Ответ 7

Вы можете сделать ссылочную оболочку очень легко, используя новое место размещения:

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

Ответ 8

Это возможно. Потому что под капотом ссылка является указателем. Следующий код напечатает "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());
}

Ответ 9

Хотя его плохая идея, поскольку она побеждает цель использования ссылок, можно напрямую изменить ссылку

const_cast< int& >(ref)=b;