2010-07-09 3 views
16

В C++,Каково значение возврата по ссылке?

function() = 10; 

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

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

+3

Не обязательно, чтобы этот синтаксис работал. Вы всегда можете вернуть объект класса прокси, у которого есть 'operator =' выполнить назначение за кулисами –

+1

, поэтому я никогда не обнимал C++ ... вы никогда не перестаете находить новые синтаксисы, которые полностью взорвут ваш разум. Обязательно перегрузите оператора: | –

+0

Вы даже можете вернуть значение и назначить временное. Вот почему Скотт Мейерс рекомендует возвращать значение const. – Philipp

ответ

20

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

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

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

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

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

2

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

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, а не возвращать ссылку.

0

std::vector имеет operator[], что не допускало бы vec[n] = m.

3

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

4

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

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

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

+0

И эта реализация трудно реорганизовать, когда вам нужно удалить или заменить some_param_ объектом другого типа. – Basilevs

2

SO облажался мой ответ

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

struct C { }; 

C f() { 
    return C(); 
} 

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

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

2

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

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 
+0

Я не знаю, почему, но я ненавижу матрицы классов (и я численный аналитик) –

7

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

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

Теперь укоротить, что

*(MyFunction()) = 10; 

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

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

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

и второй станет

MyFunction() = 10; 

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

+2

Код, который вы отправили, не является законным C++ - ссылки должны быть инициализированы. – 2010-07-09 15:19:57

1

Другой классический случай:

class Foo { 
    Foo(); 
public: 
    static Foo& getSingleton(); 
}; 
0

вы также можете достичь метод цепочки (если такое желание) U петь возвращение по ссылке.

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

named parameter idiom - другой вариант использования. Рассмотрим

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

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

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

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

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

, которые затем могут быть использованы клиентами как так

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

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

Смежные вопросы