В C++,
function() = 10;
работы, если функция возвращает переменную ссылкой.
Каковы варианты использования его?
Самый распространенный случай - реализация таких вещей, как operator[].
struct A {
int data[10];
int & operator[]( int i ) {
return data[i];
}
};
Другой случай - возврат большого объекта из класса через функцию-акселератор:
struct b {
SomeBigThing big;
const SomeBigThing & MyBig() const {
return big;
}
};
чтобы избежать накладных расходов на копирование.
ТАК напортачил с моим ответом
Вам даже не нужно возвращать ссылку:
struct C { };
C f() {
return C();
}
int main() {
C a;
f() = a; // compiles fine
}
Поскольку такое поведение довольно неожиданно, вы обычно должны возвращать константное значение или константную ссылку если у пользователя нет разумного намерения изменить результат.
Еще один классический случай:
class Foo {
Foo();
public:
static Foo& getSingleton();
};
Рассмотрим следующий код, MyFunction возвращает указатель на int,и вы устанавливаете значение int.
int *i;
i = MyFunction();
*i = 10;
Теперь сократите его до
*(MyFunction()) = 10;
Он делает то же самое, что и первый блок кода.
Вы можете смотреть на ссылку как на указатель, который всегда разыменьшена. Поэтому, если бы моя функция вернула ссылку, а не указатель, на int, блок кода frist стал бы
int &i;
i = MyFunction();
i = 10;
, а второй стал бы
MyFunction() = 10;
Это то, что я искал
Если у вас есть класс, который содержит другую структуру, может быть полезно напрямую модифицировать содержащуюся структуру:
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, чем возвращать ссылку.
Это может быть полезно при реализации аксессоров
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
Вы также можете добиться цепочки методов (если пожелаете), используя возврат по ссылке.
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);
}
Геттеры / сеттеры, например
class C
{
int some_param_;
public:
int& param() { return some_param_; }
int const& param() const { return some_param_; }
};
, но здесь вам следует выбрать some_param как общедоступное int. Контейнеры предоставляют функции, которые возвращаются по ссылке, например. vector
, чтобы можно было записать v [k] = x
.
Очень нормальный вариант использования - это когда вы пишете массив, подобный классу. Здесь вы хотите перегрузить оператор []
, чтобы можно было сделать a [0] = 10;
В этом случае вы хотите, чтобы подпись была похожа на int & operator [ ] (int index);
std :: vector
имеет оператор []
, который в противном случае не разрешил бы vec [n] = m
.
Идиома именованных параметров - это еще один случай использования. Считайте, что
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&
.