Читаем Программирование. Принципы и практика использования C++ Исправленное издание полностью

double val = v[f(x)][g(y)]; // val — значение элемента v[f(x)][g(y)]

В таком случае можно было бы повторно использовать переменную val. А что, если нам нужно и читать элемент v[f(x)][g(y)], и присваивать ему значения v[f(x)][g(y)]? В этом случае может пригодиться ссылка.

double& var = v[f(x)][g(y)]; // var — ссылка на элемент v[f(x)][g(y)]

Теперь можем как считывать, так и изменять элемент v[f(x)][g(y)] с помощью ссылки var. Рассмотрим пример.

var = var/2+sqrt(var);

Это ключевое свойство ссылок — оно может служить “аббревиатурой” объекта и использоваться как удобный аргумент. Рассмотрим пример.

// передача по ссылке (функция ссылается на полученную переменную)

int f(int& x)

{

  x = x+1;

  return x;

}

int main

{

  int xx = 0;

  cout << f(xx) << endl;  // вывод: 1

  cout << xx << endl;     // вывод: 1; функция f изменяет

                          // значение xx

  int yy = 7;

  cout << f(yy) << endl;  // вывод: 8

  cout << yy << endl;     // вывод: 8; функция f изменяет

                          // значение yy

}

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

Сравните этот пример с соответствующим примером из раздела 8.5.3.

  Совершенно очевидно, что передача по ссылке — очень мощный механизм: функции могут непосредственно оперировать с любым объектом, передаваемым по ссылке. Например, во многих алгоритмах сортировки перестановка двух значений — весьма важная операция. Используя ссылки, можем написать функцию, меняющую местами два числа типа double.

void swap(double& d1, double& d2)

{

  double temp = d1; // копируем значение d1 в переменную temp

  d1 = d2;          // копируем значение d2 в переменную d1

  d2 = temp;        // копируем старое значение d1 в переменную d2

}

int main

{

  double x = 1;

  double y = 2;

  cout << "x == " << x << " y== " << y << '\n'; // вывод: x==1 y==2

  swap(x,y);

  cout << "x == " << x << " y== " << y << '\n'; // вывод: x==2 y==1

}

В стандартной библиотеке предусмотрена функция swap для любого типа, который можно скопировать, поэтому его можно применять к любому типу. 

<p id="AutBody_Root146"><strong>8.5.6. Сравнение механизмов передачи параметров по значению и по ссылке</strong></span><span></p>

Зачем нужны передачи по значению, по ссылке и по константной ссылке. Для начала рассмотрим один формальный пример.

void f(int a, int& r, const int& cr)

{

  ++a; // изменяем локальную переменную a

  ++r; // изменяем объект, с которым связана ссылка r

  ++cr; // ошибка: cr — константная ссылка

}

Если хотите изменить значение передаваемого объекта, то должны использовать неконстантную ссылку: передача по значению создаст копию, а передача по константной ссылке предотвратит изменение передаваемого объекта. Итак, можно написать следующий код:

void g(int a, int& r, const int& cr)

{

  ++a;        // изменяем локальную переменную a

  ++r;        // изменяем объект, с которым связана ссылка r

  int x = cr; // считываем объект, с которым связана ссылка cr

}

int main

{

  int x = 0;

  int y = 0;

  int z = 0;

  g(x,y,z); // x==0; y==1; z==0

  g(1,2,3); // ошибка: ссылочный аргумент r должен быть переменным

  g(1,y,3); // OK: поскольку ссылка cr является константной,

            // можно передавать литерал

}

Итак, если хотите изменить значение объекта, передаваемого по ссылке, следует передать объект. С формальной точки зрения целочисленный литерал 2 — это значение (а точнее, r-значение, т.е. значение в правой части оператора присваивания), а не объект, хранящий значение. Для аргумента r функции f требуется l-значение (т.е. значение, стоящее в левой части оператора присваивания).

Перейти на страницу:
Нет соединения с сервером, попробуйте зайти чуть позже