Ссылка

Ссылка в программировании — это объект, указывающий на определенные данные, но не хранящий их. Получение объекта по ссылке называется разыменованием. Концептуально ссылка является указателем, но может иметь ряд отличий. Использование указателей в качестве альтернативного способа доступа к переменным таит в себе опасность - если был изменен адрес, хранящийся в указателе, то этот указатель больше не ссылается на нужное значение. Язык C предлагает альтернативу для более безопасного доступа к переменным через указатели. Объявив ссылочную переменную, можно создать объект, который, как указатель, ссылается на другое значение, но, в отличие от указателя, постоянно привязан к этому значению. Таким образом, ссылка на значение всегда ссылается на это значение.

Перегрузка операторов часто использует ссылки.

Ссылку можно объявить следующим образом:

<имя типа>& <имя ссылки> = <выражение>;
                или
<имя типа>& <имя ссылки>(<выражение>);

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

  • Ограничения на ссылки. В языке С++ существуют ограничения на работу со ссылками. Например, ссылки не могут связываться с другими ссылками. Иначе, говоря, ссылка не имеет адреса. Кроме того, невозможно создать указатель на ссылку. К битовому полю также нельзя обратиться с помощью ссылки. Независимые ссылки должны быть инициализированы в момент своего объявления. Нулевой ссылки не существует.

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

#include "iostream"
using namespace std;
void main()
{
   int ivar = 1234;   //Переменной присвоено значение.
   int *iptr = &ivar; //Указателю присвоен адрес ivar.
   int &iref = ivar;  //Ссылка ассоциирована с ivar.
   int *p = &iref;    //Указателю присвоен адрес iref.
 
   cout << "ivar = " << ivar << "\n";
   cout << "*iptr = " << *iptr <<"\n";
   cout << "iref = " << iref << "\n";
   cout << "*p = " << *p << "\n";
}

Результат работы программы:

ivar = 1234
*iptr = 1234
iref = 1234
*p = 1234

Комментарии к программе.Здесь объявляются четыре переменные. Переменнаяivar инициализирована значением 1234. Указателю на целое *iptr присвоен адресivar. Переменная iref объявлена как ссылочная. Эта переменная в качестве своего значения принимает адрес расположения в памяти переменной ivar. Оператор: cout « "iref = " « iref « "\n";

выводит на экран значение переменной ivar. Это объясняется тем, что iref - ссылка на местоположение ivar в памяти.

Последнее объявление int *p = &iref; создает еще один указатель, которому присваивается адрес, хранящийся в iref. Строки:

int *iptr = &ivar; 
          и
int *p = &iref;

дают одинаковый результат. В них создаются указатели, ссылающиеся на ivar. На рисунке проиллюстрирована взаимосвязь переменных из приведенной программы:

При использовании ссылок следует помнить одно правило: однажды инициализировав ссылку ей нельзя присвоить другое значение!

Ссылки в качестве результатов функций

Здесь мы рассмотрим использование ссылок в качестве результатов функций. Далее представлен ряд редакторов, рекомендуемых для использования и их основные возможности. Функции могут возвращать ссылки на объекты при условии, что эти объекты существуют, когда функция неактивна. Таким образом, функции не могут возвращать ссылки на локальные автоматические переменные. Например, для функции, объявленной как:

double &rf(int p);

необходим аргумент целого типа, и она возвращает ссылку на объект double, предположительно объявленный где-то в другом месте. Проиллюстрируем сказанное конкретными примерами.

  • Пример 1. Заполнение двумерного массива одинаковыми числами.
#include "iostream"

using namespace std;
int a[10][2];
void main ()
{
	int & rf(int index); //Прототип функции.
	int b;
	cout << "Заполнение двумерного массива. ";
	cout << "Первый столбец заполняется обычным способом, ";
	cout << "а второй - через функцию.\n";
	for (int i=0;i<10;i++)
	{
	  cout << i+1 << "-й элемент: ";
	  cin >> b;
	  a[i][0] = b;
	  rf(i) = b;
	}
	cout << "Вывод двумерного массива.\n";
	cout << "1-й столбец   2-й столбец" << "\n";
	for (i=0;i<10;i++)
		cout << a[i][0] << "\t\t" << rf(i) << "\n";
}

int &rf(int index)
{
  return a[index][1]; //Возврат ссылки на элемент массива.
}

Здесь объявляется глобальный двумерный массив a, состоящий из целых чисел. В начале функции main() содержится прототип ссылочной функции rf(), которая возвращает ссылку на целое значение второго столбца массива a, которое однозначно идентифицируется параметром-индексом index. Так как функция rf() возвращает ссылку на целое значение, то имя функции может оказаться слева от оператора присваивания, что продемонстрировано в строке:

rf(i) = b;
PQ VPS сервера в 28+ странах.