Лекции.ИНФО


При выполнении этой программы получаем такой результат.



Старое значение переменной val: 1

Новое значение переменной val: 10

Обратите особое внимание на определение функции f().

void f (int &i)

{

 i = 10; // Модификация аргумента, заданного при вызове.

}

Итак, рассмотрим объявление параметра i. Его имени предшествует символ который "превращает" переменную i в ссылочный параметр. (Это объявление также используется в прототипе функции.) Инструкция

i = 10;

(в данном случае она одна составляет тело функции) не присваивает переменной i значение 10. В действительности значение 10 присваивается переменной, на которую ссылается переменная i (в нашей программе ею является переменная val). Обратите внимание на то, что в этой инструкции не используется оператор который необходим при работе с указателями. Применяя ссылочный параметр, вы тем самым уведомляете С++-компилятор о передаче адреса (т.е. указателя), и компилятор автоматически разыменовывает его за вас. Более того, если бы вы попытались "помочь" компилятору, использовав оператор то сразу же получили бы сообщение об ошибке (и вправду "ни одно доброе дело не остается безнаказанным").

Поскольку переменная i была объявлена как ссылочный параметр, компилятор автоматически передает функции f() адрес любого аргумента, с которым вызывается эта функция. Таким образом, в функции main() инструкция

F(val); // Передаем адрес переменной val функции f().

передает функции f() адрес переменной val (а не ее значение). Обратите внимание на то, что при вызове функции f() не нужно предварять переменную val оператором "&". (Более того, это было бы ошибкой.) Поскольку функция f() получает адрес переменной val в форме ссылки, она может модифицировать значение этой переменной.

Чтобы проиллюстрировать реальное применение ссылочных параметров (и тем самым продемонстрировать их достоинства), перепишем нашу старую знакомую функцию swap() с использованием ссылок. В следующей программе обратите внимание на то, как функция swap() объявляется и вызывается.

#include <iostream>

using namespace std;

// Объявляем функцию swap() с использованием ссылочных параметров.

void swap(int &х, int &у);

Int main()

{

 int i, j;

 i = 10; j = 20;

 cout << " Исходные значения переменных i и j: ";

 cout << i << ' ' << j << '';

 swap (j, i);

 cout << " Значения переменных i и j после обмена: ";

 cout << i << ' ' << j << '';

 return 0;

}

/* Здесь функция swap() определяется в расчете на вызов по ссылке, а не на вызов по значению. Поэтому она может выполнить обмен значениями двух аргументов, с которыми она вызывается.

*/

void swap(int &х, int &у)

{

 int temp;

 temp = x; // Сохраняем значение, расположенное по адресу х.

 х = у; // Помещаем значение, хранимое по адресу у, в адрес х.

 у = temp; // Помещаем значение, которое раньше хранилось по адресу х, в адрес у.

}

Опять таки, обратите внимание на то, что объявление х и у ссылочными параметрами избавляет вас от необходимости использовать оператор при организации обмена значениями. Как уже упоминалось, такая "навязчивость" с вашей стороны стала бы причиной ошибки. Поэтому запомните, что компилятор автоматически генерирует адреса аргументов, используемых при вызове функции swap(), и автоматически разыменовывает ссылки х и у.

Итак, подведем некоторые итоги. После создания ссылочный параметр автоматически ссылается (т.е. неявно указывает) на аргумент, используемый при вызове функции. Более того, при вызове функции не нужно применять к аргументу оператор Кроме того, в теле функции ссылочный параметр используется непосредственно, т.е. без использования оператора Все операции, включающие ссылочный параметр, автоматически выполняются над аргументом, используемым при вызове функции.

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

Объявление ссылочных параметров

В изданной в 1986 г. книге Язык программирования C++ (в которой был впервые описан синтаксис C++) Бьерн Страуструп представил стиль объявления ссылочных параметров, одобренный другими программистами. В соответствии с этим стилем оператор "&" связывается с именем типа, а не с именем переменной. Например, вот как выглядит еще один способ записи прототипа функции swap().

void swap(int& х, int& у);

Нетрудно заметить, что в этом объявлении символ "&" прилегает вплотную к имени типа int, а не к имени переменной х.

Некоторые программисты определяют в таком стиле и указатели, связывая символ "*" с типом, а не с переменной, как в этом примере.

float* р;

Приведенные объявления отражают желание некоторых программистов иметь в C++ отдельный тип ссылки или указателя. Но дело в том, что подобное связывание символа "&" или "*" с типом (а не с переменной) не распространяется, в соответствии с формальным синтаксисом C++, на весь список переменных, приведенных в объявлении, что может привести к путанице. Например, в следующем объявлении создается один указатель (а не два) на целочисленную переменную.

int* а, b;

Здесь b объявляется как целочисленная переменная (а не как указатель на целочисленную переменную), поскольку, как определено синтаксисом C++, используемый в объявлении символ "*" или "&" связывается с конкретной переменной, которой он предшествует, а не с типом, за которым он следует.

Важно понимать, что для С++-компилятора абсолютно безразлично, как именно вы напишете объявление: int *р или int* р. Таким образом, если вы предпочитаете связывать символ "*" или "&" с типом, а не переменной, поступайте, как вам удобно. Но, чтобы избежать в дальнейшем каких-либо недоразумений, в этой книге мы будем связывать символ "*" или "&" с именем переменной, а не с именем типа.

Важно! В языке С ссылки не поддерживаются. Поэтому единственный способ обеспечить в языке С вызов по ссылке состоит в использовании указателей, как было показано выше (см. первую версию функции swap()). Преобразуя С-код в С++-код, вам стоит вместо параметров-указателей использовать, где это возможно, ссылки.

Возврат ссылок

Функция может возвращать ссылку. В программировании на C++ предусмотрено несколько применений для ссылочных значений, возвращаемых функциями. Сейчас мы продемонстрируем только некоторые из них, а другие рассмотрим ниже в этой книге, когда познакомимся с перегрузкой операторов.

Если функция возвращает ссылку, это означает, что она возвращает неявный указатель на значение, передаваемое ею в инструкции return. Этот факт открывает поразительные возможности: функцию, оказывается, можно использовать в левой части инструкции присваивания! Например, рассмотрим следующую простую программу.

// Возврат ссылки.

#include <iostream>

using namespace std;

double &f();

double val = 100.0;

Int main()

{

 double newval;

 cout << f() << ''; // Отображаем значение val.

 newval = f(); // Присваиваем значение val переменной newval.

 cout << newval << ''; // Отображаем значение newval.

 f() = 99.1; // Изменяем значение val.

 cout << f() << ''; // Отображаем новое значение val.

 return 0;

}

double &f()

{

 return val; // Возвращаем ссылку на val.

}

Вот как выглядят результаты выполнения этой программы.

99.1

Рассмотрим эту программу подробнее. Судя по прототипу функции f(), она должна возвращать ссылку на double-значение. За объявлением функции f() следует объявление глобальной переменной val, которая инициализируется значением 100. При выполнении следующей инструкции выводится исходное значение переменной val.

cout << f() << ''; // Отображаем значение val.

После вызова функция f() возвращает ссылку на переменную val. Поскольку функция f() объявлена с "обязательством" вернуть ссылку, при выполнении строки

Return val; // Возвращаем ссылку на val.

автоматически возвращается ссылка на глобальную переменную val. Эта ссылка затем используется инструкцией cout для отображения значения val.

При выполнении строки

newval = f(); //Присваиваем значение val переменной newval.

ссылка на переменную val, возвращенная функцией f(), используется для присвоения значения val переменной newval.









Читайте также:

  1. A. Притяжения и отталкивания, силы отталкивания больше на малых расстояниях, чем силы притяжения. Б. Притяжения и отталкивания, силы отталкивания меньше на малых расстояниях, чем силы притяжения.
  2. Adjective and adverb. Имя прилагательное и наречие. Степени сравнения.
  3. D. Правоспособность иностранцев. - Ограничения в отношении землевладения. - Двоякий смысл своего и чужого в немецкой терминологии. - Приобретение прав гражданства русскими подданными в Финляндии
  4. D. ПРЕИМУЩЕСТВА ПРИСОЕДИНЕНИЯ К ГААГСКОМУ СОГЛАШЕНИЮ
  5. F70.99 Умственная отсталость легкой степени без указаний на нарушение поведения, обусловленная неуточненными причинами
  6. F71.98 Умственная отсталость умеренная без указаний на нарушение поведения, обусловленная другими уточненными причинами
  7. I Использование заемных средств в работе предприятия
  8. I. Методические принципы физического воспитания (сознательность, активность, наглядность, доступность, систематичность)
  9. I. О НОВОПРИБЫВШИХ ГРАЖДАНАХ.
  10. I. Предприятия крупного рогатого скота
  11. I. Придаточные, которые присоединяются непосредственно к главному предложению, могут быть однородными и неоднородными.
  12. I. СИЛЬНЫЕ СТОРОНЫ ПРЕДПРИЯТИЯ


Последнее изменение этой страницы: 2016-03-17; Просмотров: 93;


lektsia.info 2017 год. Все права принадлежат их авторам! Главная