C передать ссылку на параметр

0

как я знаю в 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;
}
Теги:

5 ответов

3
Лучший ответ

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

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

  • 0
    значит ли это, что z является локальным переменным для claculateStuffAndReturnAnAForMe (): каждое изменение в исходной переменной (z) будет влиять на данные члена класса A (m_x) и наоборот? (уничтожение z будет влиять на A :: m_x, а любые функции-члены класса изменения A, выполняемые на m_x, будут влиять на z) !!!
  • 0
    спасибо слишком много. ты прояснил это
Показать ещё 3 комментария
1

В cout<<"x= "<<x<<endl; вы печатаете локальную переменную main(), тогда как в a.print() вы печатаете локальную переменную x объекта a, которая уменьшает функцию члена DecrX().

  • 0
    хорошо, спасибо
1

Проблема в том, что тот факт, что ваш конструктор принимает переменную по ссылке, здесь не имеет значения:

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. Посмотрите: Должен ли я предпочитать указатели или ссылки в данных члена?

  • 0
    хорошо, спасибо, теперь понятно
  • 0
    @ raindrop7: я отредактировал свой ответ, см. последний абзац.
1

Вы изменяете копию не оригинал, а не сам, поэтому оригинал не будет изменен. Читать комментарии:

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

  • 0
    хорошо, спасибо, я понял. значит ли это, что A :: x - это не та же самая переменная int x (переданная в) в памяти?
  • 0
    @ raindrop7: Да, в вашем коде они не совпадают. Но во втором коде, который я написал, int &x; будет хранить ссылку на оригинал x .
Показать ещё 3 комментария
0

Проблема здесь в том, что вы передаете ссылку, но затем назначаете ее члену класса x. Выполнение этого не будет содержать ссылки. А элемент x и x в основном полностью не связаны. Я надеюсь в этом есть смысл. Чтобы исправить это, вы можете сделать указатель xa класса.

  • 0
    хорошо, спасибо. но последний вопрос: какой смысл писать A (int & x) и A (int x), если я объявляю int m_x данными члена ???
  • 0
    Вы имеете в виду, зачем использовать A (int & x), если ссылка все равно теряется при использовании int m_x? Хорошо, один случай, когда вы могли бы сделать это, когда параметр содержит экземпляр большого класса с большим количеством данных. Когда вы используете A (x), он копирует весь объект в функцию, но при использовании A (& x) он только копирует ссылку. Поэтому передача параметра по ссылке происходит быстрее, когда вы имеете дело с большими объектами.
Показать ещё 1 комментарий

Ещё вопросы

Сообщество Overcoder
Наверх
Меню