0

as I know in c++ when you pass a variable by reference means that we pass the very variable not a copy of it. so if a function that takes a refernce as a parameter we know that any change that that function does on the parameter will affect the original variable(variable passed in). but I'm stuck now: I have a member function that takes a reference to int this member function void DecrX(int &x) decrements x when it is called. the problem i get is that the original variable always never affected???!!! eg:

#include <iostream>
using namespace std;

class A
{
public:
    A(int &X):x(X){}
    int &getX(){return x;}
    void DecrX(){--x;}
    void print(){cout<<"A::x= "<<x<<endl<<endl;}
private:
    int x;
};

int main()
{

int x=7;
cout<<"x= "<<x<<endl;
A a(x);//we passed the x by reference
a.DecrX();// here normally DecrX() affect the original x
a.print();//here it is ok as we thought
a.DecrX();
a.DecrX();
a.print();
cout<<"x= "<<x<<endl;//why x is still 7 not decremented

cout<<endl;
return 0;
}
Raindrop7
  • 3,889
  • 3
  • 16
  • 27

5 Answers5

3

You can make this problem easier for yourself to understand by being a little more verbose, specifically, give your member variables more distinct names.

class A
{
public:
    A(int& x) : m_x(x) {}
    const int& getX() const { return m_x; }
    void DecrX() { --m_x; }
    void print() {cout << "A::m_x= " << m_x << endl << endl;}
private:
    int m_x;
};

Now, lets look at this more carefully. "m_x" (member x) is of type "int". It's not a reference. It's a value.

A(int& x)

Declares a constructor which takes a reference to a variable and calls this reference "x".

: m_x(x)

Initializes member x, an integer value, with the value of the reference called x.

The problem is that your member m_x is itself a value and not a reference.

class A
{
public:
    A(int& x) : m_x(x) {}
    const int& getX() const { return m_x; }
    void DecrX() { --m_x; }
    void print() {cout << "A::m_x= " << m_x << endl << endl;}
private:
    int& m_x;
};

BEWARE: Creating objects which take references to things can be a nightmare.

#include <iostream>

class A
{
public:
    A(int& x) : m_x(x) {}
    const int& getX() const { return m_x; }
    void DecrX() { --m_x; }
    void print() { std::cout << "A::m_x= " << m_x << std::endl << std::endl; }
private:
    int& m_x;
};

A calculateStuffAndReturnAnAForMe(int x, int y)
{
    int z = x + y;
    A a(z);
    return a;
}

int main()
{
    A badData = calculateStuffAndReturnAnAForMe(5, 10);
    badData.print(); // badData's m_x is a reference to z, which is no-longer valid.
    std::string input;
    std::cout << "Enter your name: ";
    std::cin >> input;
    std::cout << std::endl << "You entered: " << input << std::endl;
    badData.print();
}

In this case, the "a" we return has a reference to stack-variable "z" but "z" goes away when we leave the function. The result is Undefined Behavior.

See live demo: http://ideone.com/T279v7

kfsone
  • 23,617
  • 2
  • 42
  • 74
  • so does this mean tha z being a local varaible to claculateStuffAndReturnAnAForMe(): each change occurs to the original variable (z) will affect the member data of class A (m_x) and vice versa? (the destruction of z will affect A::m_x and any change class A's member functions do on m_x will affect z)!!! – Raindrop7 Oct 12 '13 at 21:56
  • When we say "m_x references z" the compiler actually uses a pointer, call it xRef, pointing to "&z". When we use "m_x" the compiler substitutes in "*xRef". When we leave calculateStuff, "z" goes out of scope and because its on the stack it's location will be re-used by new variables/function calls. m_x's pointer, xRef, continues to point to that location though. So you have to be very careful when you take references to things that your reference doesn't outlive your object. – kfsone Oct 13 '13 at 05:43
  • Here is a really great explanation of the problem with references to things that go out of scope: http://stackoverflow.com/questions/6441218/can-a-local-variables-memory-be-accessed-outside-its-scope/6445794#6445794 – kfsone Oct 13 '13 at 05:56
  • it is as if we write: class A{public: A(int x): m_X(x){} int getM_X()const {return m_x;} private: int &m_X;}; int main(){A a(7); cout<<"m_x= "< – Raindrop7 Oct 14 '13 at 12:52
1

In cout<<"x= "<<x<<endl; you print the local variable of main(), whereas in a.print() lines you print the local variable x of object a, which the member function DecrX() decreases.

Igor Popov
  • 2,588
  • 17
  • 20
1

You're modifying a copy not the original not itself, so the original will not be changed. Read comments:

A(int &X) : x (X) {}   // This copies modifiable `X` into `x`.
            |  ^
            |  |
            +--+

void DecrX(){--x;}    // This decrements `x` not referenced `X`

To have the ability of modifying the original variable, you should declare a reference:

class A
{
public:
    A(int &X):x(X){}

    void DecrX(){--x;}

private:
    int &x; // <<------------ A reference
        ^
};

Be careful, life time of passed variable should be longer than the receiver object of A.

masoud
  • 55,379
  • 16
  • 141
  • 208
  • ok thanx I got it. so does this mean A::x is not the same variable int x (passed in) in memory? – Raindrop7 Oct 12 '13 at 21:09
  • @raindrop7: In your code, yes, they're not the same. But in the second code that I wrote `int &x;` will store a reference to the original `x`. – masoud Oct 12 '13 at 21:16
  • ok thnx. I never saw a reference declared as a member data. could you say if we declare a pointer as member data will do the same as you declared the reference int &x? – Raindrop7 Oct 12 '13 at 21:44
  • @raindrop7: Yes, a pointer can do same thing, **but** it's strongly recommended to avoid pointers, a reference is less dangerous to use. Read last sentence in my answer. – masoud Oct 12 '13 at 22:07
  • at last could you explain the difference between A(int x) and A(int &x) knowing that A has-a int m_x as a member data not a reference???? – Raindrop7 Oct 12 '13 at 22:23
1

The problem is that the fact that your constructor takes variable by reference is irrelevant here:

class A
{
public:
    A(int &X):x(X){}      // <-- initializes member x by copying passed argument
    void DecrX(){--x;}    // <-- decrements member of class A
    ...
    int x;
};

to achieve what you actually described, you need to define member x as a reference as well:

int& x;

"if we declare a pointer as member data will do the same as you declared the reference int &x?"

The pointer is initialized using an address. Important to realize is that NULL is perfectly valid value while reference can not be initialized by other means than using valid variable / object. Note that once you declare member x as a reference, you introduce a constraint that instance of class A can not be created without valid int variable. Have a look at: Should I prefer pointers or references in member data?

Community
  • 1
  • 1
LihO
  • 41,190
  • 11
  • 99
  • 167
0

The problem here is that you pass the reference, but then assign it to the class member x. Doing this will not keep the reference. And the x class member and the x in the main are totally unrelated. I hope this makes sense. To fix this, you could make the class member x a pointer.

SilverTear
  • 695
  • 7
  • 18
  • ok thnx alot. but the last question: what is the point in writting A(int &x) and A(int x) if I declare int m_x as member data??? – Raindrop7 Oct 12 '13 at 22:00
  • You mean why use A(int &x) when the reference is lost anyway when using int m_x? Well, one case where you could do this is when the parameter cointains an instance of a big class with many data. When you use A(x), it will copy the whole object into the function, but when using A(&x) it will only copy a refence. So passsing a parameter by reference is faster when you deal with big objects. – SilverTear Oct 13 '13 at 21:33
  • ok thnx it is clear now. and does this mean any change to "int &x" will affect the original variable? – Raindrop7 Oct 14 '13 at 12:56