Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
lesson_12_13.doc
Скачиваний:
0
Добавлен:
01.07.2025
Размер:
365.57 Кб
Скачать
  1. Ссылки.

Ссылочные переменные

Ссылка представляет собой имя, которое является псевдонимом, или альтернативным именем, для ранее объявленной переменной. Например, если вы делаете twain ссылкой на переменную clemens, можно взаимозаменяемо использовать эти имена для представления данной переменной. В чем смысл применения альтернативного имени? Не в том ли, чтобы помочь-тем программистам, которые не удовлетворены сделанным ими выбором имен переменных? Вполне возможно, однако, основное назначение ссылок — их использование в качестве формальных аргументов функций. Применяя ссылку в качестве аргумента, функция работает с исходными данными, а не с их копиями. Ссылки представляют собой удобную альтернативу указателям при обработке крупных структур посредством функций.

Создание ссылочных переменных

Как уже упоминалось, в языках С и C++ символ & используется для обозначения адреса переменной. Язык C++ придает символу & дополнительный смысл и задействует его для объявления ссылок. Например, чтобы rodents стало альтернативным именем для переменной rats, необходимо написать следующее:

int rats;

int & rodents = rats; // rodents становится псевдонимом имени rats

В таком контексте символ & не является операцией взятия адреса. В этом случае & воспринимается как часть идентификатора типа данных. Подобно тому, как выражение char * в объявлении означает указатель на char, выражение int & представляет собой ссылку на int. Объявление ссылки позволяет взаимозаменяемо использовать идентификаторы rats и rodents. Они ссылаются на одно и то же значение, а также на один и тот же адрес памяти.

#include <iostream>

using namespace std;

void main ()

{

int x = 1;

int & y=x; // y является ссылкой

cout << "x = " << x;

cout << ", y = " << y << endl;

y++;

cout << "x = " << x;

cout << ", y = " << y << endl;

cout << "x address = " << &x;

cout << ", y address = " << &y << endl;

cin.get();

cin.get();

}

Вывод:

x = 1, y = 1

x = 2, y = 2

x address = 0022FF0C, y address = 0022FF0C

Для продолжения нажмите любую клавишу . . .

Например, можно создать как ссылку, так и указатель, чтобы ссылаться на переменную x:

int x = 101;

int & y = x; // y - ссылка

int * ptr = &x; // ptr - указатель

Затем выражения y и *ptr могут заменять имя x, а выражения &y и ptr могут подменять обозначение &x.

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

int x;

int & y;

y = x; // подобное не допускается

На заметку!

При объявлении ссылочную переменную необходимо инициализировать.

Ссылка скорее похожа на указатель const; ее следует инициализировать в момент создания, и она остается привязанной к определенной переменной до конца программы. Таким образом, конструкция

int & y = x;

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

int * const pr = &x;

В данном случае ссылка y играет ту же роль, что и выражение *рг.

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

Ссылки как параметры функций

Чаще всего ссылки используются в качестве параметров функции, при этом имя переменной в функции становится псевдонимом переменной в вызывающей программе. Такой метод передачи аргументов называется передачей по ссылке. Передача параметров по ссылке позволяет вызываемой функции получить доступ к переменным в вызывающей функции.

Передача по значению

void sneezy(int x);

int main()

{

int times = 20;  Создает переменную по имени times

sneezy(times); и присваивает ей значение 20 20

…. times

} две переменных

два имени

void sneezy(int x)

{ Создает переменную по имени х

….  и присваивает ей передаваемое 20

} значение 20 x

Передача по ссылке

void grumpy (int &x) ;

int main()

{

int times =20;  Создает переменную по имени times 20 Одна переменная

grumpy(times); и присваивает ей значение 20 times, х два имени

}

void grumpy(int &x)

{

….  Делает х псевдонимом для times

}

Как уже упоминалось ранее, ссылочную переменную необходимо инициализировать при ее определении. Вызов функции инициализирует свои параметры значениями аргументов, передаваемых в вызове. Это значит, что следующий вызов функции инициализирует формальный параметр х значением times:

grumpy(times);

Когда целесообразно использовать ссылочные аргументы

Есть две главных причины использовать ссылочные аргументы:

• чтобы позволить изменять объект данных в вызывающей функции;

• чтобы ускорить работу программы за счет передачи ссылки вместо полной копии объекта данных.

Вторая причина наиболее важна для крупных объектов данных, таких как структуры и объекты классов. По этим же двум причинам в качестве аргумента может использоваться указатель. Это оправдано, поскольку аргументы-ссылки, по сути, являются лишь альтернативным интерфейсом для кода, где применяются указатели. Итак, в каких случаях следует использовать ссылку, указатель или передачу по значению? Ниже приводятся основные рекомендации.

Функция использует передаваемые данные без их изменения в перечисленных

ниже ситуациях.

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

• Если объект данных представляет собой массив, используйте указатель, поскольку это единственный вариант. Объявите указатель с квалификатором const.

• Если объект данных является структурой приемлемого размера, используйте const-указатель или const-ссылку для увеличения эффективности программы. В этом случае удастся сохранить время и пространство, необходимое для копирования структуры или строения класса. Объявите указатель или ссылку с квалификатором const.

• Если объект данных является объектом класса, используйте ссылку с квалификатором const. Семантика строения класса часто требует применения ссылки. Эта главная причина добавления этого новшества в язык C++. Таким образом, стандартом является передача объектов класса по ссылке. Функция изменяет данные вызывающей функции в следующих ситуациях.

• Если объект данных относится к одному из встроенных типов, используйте указатель. Если в коде встретилось выражение вида fixit (&х), где х имеет тип int, это явно означает, что функция должна изменять значение х.

• Если объект данных представляет собой массив, остается один выбор — указатель.

• Если объект данных является структурой, можно использовать ссылку или указатель.

• Когда объект данных представляет собой объект класса, следует применять

ссылку.

Конечно, это лишь рекомендации, и могут существовать причины для других решений. Например, объект сіп использует ссылки на базовые типы данных, поэтому вместо записи сіп » &n можно применять запись сіп » n.

_____________________________________________________________________

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

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

Язык 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. На рис.1 проиллюстрирована взаимосвязь переменных из приведенной программы:

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

a) int iv = 3; b) iref++; c) iref = 4321;

iref = iv;

приведут к изменению переменной ivar!

Замечания.

  • 1. В отличие от указателей, которые могут быть объявлены неинициализированными или установлены в нуль (NULL), ссылки всегда ссылаются на объект. Для ссылок ОБЯЗАТЕЛЬНА инициализация при создании и не существует аналога нулевого указателя.

  • 2. Ссылки нельзя инициализировать в следующих случаях:

    • при использовании в качестве параметров функции.

    • при использовании в качестве типа возвращаемого значения функции.

    • в объявлениях классов.

  • 3. Не существует операторов, непосредственно производящих действия над ссылками!

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]