как я знаю в c++, когда вы передаете переменную по ссылке, мы передаем очень переменную, а не ее копию. поэтому, если функция, которая принимает параметр refernce в качестве параметра, мы знаем, что любое изменение, которое эта функция оказывает на параметр, будет влиять на исходную переменную (переменная, переданная в). но я застрял сейчас: у меня есть функция-член, которая принимает ссылку на int эту функцию-член void DecrX (int & x) уменьшает x при ее вызове. проблема в том, что исходная переменная всегда никогда не затрагивалась??? !!! например:
#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;
}
Вы можете сделать эту проблему проще для себя, понимая, будучи немного более подробным, в частности, придайте переменным-членам более четкие имена.
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;
};
Теперь давайте посмотрим на это более тщательно. "m_x" (член x) имеет тип "int". Это не ссылка. Это значение.
A(int& x)
Объявляет конструктор, который ссылается на переменную и вызывает эту ссылку "x".
: m_x(x)
Инициализирует элемент x, целочисленное значение, со значением ссылки, называемой x.
Проблема в том, что ваш член m_x сам по себе является значением, а не ссылкой.
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;
};
ОСТОРОЖНО: Создание объектов, которые ссылаются на вещи, может стать кошмаром.
#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 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();
}
В этом случае возвращаемое "a" имеет ссылку на стек-переменную "z", но "z" исчезает, когда мы покидаем функцию. Результатом является Undefined Behavior.
Смотрите демо-версию: http://ideone.com/T279v7
В cout<<"x= "<<x<<endl;
вы печатаете локальную переменную main()
, тогда как в a.print()
вы печатаете локальную переменную x
объекта a
, которая уменьшает функцию члена DecrX()
.
Проблема в том, что тот факт, что ваш конструктор принимает переменную по ссылке, здесь не имеет значения:
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;
};
для достижения того, что вы на самом деле описали, вам нужно также определить элемент x
как ссылку:
int& x;
"если мы объявим указатель в качестве данных-членов, будем делать то же самое, что вы указали ссылку int &x
?"
Указатель инициализируется с использованием адреса. Важно понимать, что NULL
является вполне допустимым значением, а ссылка не может быть инициализирована другими способами, кроме использования действительной переменной/объекта. Обратите внимание, что после объявления элемента x
в качестве ссылки вы вводите ограничение, что экземпляр класса A
не может быть создан без действительной переменной int
. Посмотрите: Должен ли я предпочитать указатели или ссылки в данных члена?
Вы изменяете копию не оригинал, а не сам, поэтому оригинал не будет изменен. Читать комментарии:
A(int &X) : x (X) {} // This copies modifiable 'X' into 'x'.
| ^
| |
+--+
void DecrX(){--x;} // This decrements 'x' not referenced 'X'
Чтобы иметь возможность изменять исходную переменную, вы должны объявить ссылку:
class A
{
public:
A(int &X):x(X){}
void DecrX(){--x;}
private:
int &x; // <<------------ A reference
^
};
Будьте осторожны, срок службы передаваемой переменной должен быть длиннее, чем объект приемника A
int &x;
будет хранить ссылку на оригинал x
.
Проблема здесь в том, что вы передаете ссылку, но затем назначаете ее члену класса x. Выполнение этого не будет содержать ссылки. А элемент x и x в основном полностью не связаны. Я надеюсь в этом есть смысл. Чтобы исправить это, вы можете сделать указатель xa класса.