Каково значение возврата ссылкой?

В C++,

function() = 10;

работы, если функция возвращает переменную ссылкой.

Каковы варианты использования его?

16
задан We love stackoverflow 9 July 2010 в 10:00
поделиться

11 ответов

Самый распространенный случай - реализация таких вещей, как operator[].

struct A {
    int data[10];
    int & operator[]( int i ) {
         return data[i];
    }
};

Другой случай - возврат большого объекта из класса через функцию-акселератор:

struct b {
    SomeBigThing big;
    const SomeBigThing & MyBig() const {
         return big;
    }
};

чтобы избежать накладных расходов на копирование.

20
ответ дан 30 November 2019 в 16:18
поделиться

ТАК напортачил с моим ответом

Вам даже не нужно возвращать ссылку:

struct C { };

C f() {
  return C();
}

int main() {
  C a;
  f() = a;  // compiles fine
}

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

2
ответ дан 30 November 2019 в 16:18
поделиться

Еще один классический случай:

class Foo {
  Foo();
public:
  static Foo& getSingleton();
};
1
ответ дан 30 November 2019 в 16:18
поделиться

Рассмотрим следующий код, MyFunction возвращает указатель на int,и вы устанавливаете значение int.

int  *i;
i = MyFunction();
*i = 10;

Теперь сократите его до

*(MyFunction()) = 10;

Он делает то же самое, что и первый блок кода.

Вы можете смотреть на ссылку как на указатель, который всегда разыменьшена. Поэтому, если бы моя функция вернула ссылку, а не указатель, на int, блок кода frist стал бы

int  &i;
i = MyFunction();
i = 10;

, а второй стал бы

MyFunction() = 10;

Это то, что я искал

7
ответ дан 30 November 2019 в 16:18
поделиться

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

struct S
{
    int value;
};

class C
{
    public:

        S& ref() { return m_s; }

    private:

        S m_s;
};

Позволяет вам написать что-то вроде:

void foo()
{
    C c;

    // Now you can do that:

    c.ref().value = 1;
}

Примечание: в этом примере может быть проще напрямую сделать m_s public, чем возвращать ссылку.

2
ответ дан 30 November 2019 в 16:18
поделиться

Это может быть полезно при реализации аксессоров

class Matrix
{
   public:
      //I skip constructor, destructor etc

      int & operator ()(int row, int col)
      {
         return m_arr[row + col * size];
      }

   private:
      int size;
      int * m_arr;
}

Matrix m(10);
m(1,0) = 10;  //assign a value to row 1, col 0
2
ответ дан 30 November 2019 в 16:18
поделиться

Вы также можете добиться цепочки методов (если пожелаете), используя возврат по ссылке.

class A
{
public:
    A& method1()
    {
        //do something
        return *this;   //return ref to the current object
    }
    A& method2(int i);
    A& method3(float f);  //other bodies omitted for brevity
};

int main()
{
    A aObj;
    aObj.method1().method2(5).method3(0.75);

    //or use it like this, if you prefer
    aObj.method1()
        .method2(5)
        .method3(0.75);
}
0
ответ дан 30 November 2019 в 16:18
поделиться

Геттеры / сеттеры, например

class C
{
    int some_param_;
public:
    int& param() { return some_param_; }
    int const& param() const { return some_param_; }
};

, но здесь вам следует выбрать some_param как общедоступное int. Контейнеры предоставляют функции, которые возвращаются по ссылке, например. vector :: operator [] , чтобы можно было записать v [k] = x .

4
ответ дан 30 November 2019 в 16:18
поделиться

Очень нормальный вариант использования - это когда вы пишете массив, подобный классу. Здесь вы хотите перегрузить оператор [] , чтобы можно было сделать a [0] = 10; В этом случае вы хотите, чтобы подпись была похожа на int & operator [ ] (int index);

3
ответ дан 30 November 2019 в 16:18
поделиться

std :: vector имеет оператор [] , который в противном случае не разрешил бы vec [n] = m .

0
ответ дан 30 November 2019 в 16:18
поделиться

Идиома именованных параметров - это еще один случай использования. Считайте, что

class Foo
{
public:
    Foo(
        int lions,
        float tigers,
        double bears,
        std::string zookeeper
    );
};

пользователям этого класса нужно помнить положение каждого параметра

Foo foo( 1, 2.0, 5, "Fred" );

которое может быть неочевидным без просмотра заголовка. По сравнению с классом-создателем, таким как so

class CreateFoo
{
friend class Foo;
public:
    CreateFoo();

    CreateFoo& lions(int lions) {
        _lions = lions;
         return *this;
    }

    CreateFoo& tigers(float tigers) {
        _tigers = tigers;
        return *this;
    }

    CreateFoo& bears(double bears) {
        _bears = bears;
        return *this;
    }

    CreateFoo& zookeeper(const std::string& zookeeper) {
        _zookeeper = zookeeper;
        return *this;
    }

private:
    int _lions;
    float _tigers;
    double _bears;
    std::string _zookeeper;
};

который затем может быть использован клиентами, такими как so

Foo foo = CreateFoo().
    lions(1).
    tigers(2.0).
    zookeeper("Fred").
    bears(5)
    ;

если предположить, что Foo имеет конструктор, принимающий const CreateFoo&.

0
ответ дан 30 November 2019 в 16:18
поделиться
Другие вопросы по тегам:

Похожие вопросы: