web-dev-qa-db-fra.com

Comment puis-je changer la variable à laquelle se réfère une référence C ++?

Si j'ai ceci:

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

Comment puis-je faire ref faire référence à b après ce code?

61
Taru

Ce n'est pas possible, et c'est par conception . Les références ne peuvent pas être rebondies.

78
Björn Pollex

Avec C++ 11, il y a le nouveau (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);
}

Ceci est également utile pour stocker des références dans des conteneurs.

66
David C. Bishop

Vous ne pouvez pas réaffecter une référence, mais si vous recherchez quelque chose qui offrirait des capacités similaires à cela, vous pouvez faire un pointeur à la place.

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.

Vous pouvez obtenir ou définir la valeur dans le pointeur avec:

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

Vous ne pouvez pas réaffecter une référence.

9
Griwes

Ce n'est pas possible comme vous le souhaitez. C++ ne vous permet tout simplement pas de relier à quoi pointe une référence.

Cependant, si vous voulez utiliser la ruse, vous pouvez presque la simuler avec une nouvelle portée ( JAMAIS faites-le dans un vrai programme):

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

Formellement parlant, cela est impossible car il est interdit par la conception. Arbitrairement parlant, c'est possible.

Une référence est stockée sous forme de pointeur, vous pouvez donc toujours changer où elle pointe tant que vous savez comment obtenir son adresse. De même, vous pouvez également modifier la valeur des variables const, des variables membres const ou même des variables membres privées lorsque vous n'y avez pas accès.

Par exemple, le code suivant a modifié la référence de membre privé const de la classe A:

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

Sortie du programme:

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

Comme vous pouvez voir que a.i1 pointe initialement sur i, après le changement, il pointe sur j.

Cependant, cela est considéré comme dangereux et donc non recommandé, car il va à l'encontre de l'objectif initial de l'encapsulation des données et de la POO. Cela ressemble plus au piratage d'adresse mémoire.

5
xuancong84

Vous pouvez rendre un wrapper de référence très facile en utilisant le nouveau placement:

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
3
Taster

C'est possible. Parce que sous le capot, la référence est un pointeur. Le code suivant imprimera "bonjour le monde"

#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());
}
3
Zhaolin Feng