Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
2009 лекции ПЯВУ часть1.doc
Скачиваний:
22
Добавлен:
27.03.2015
Размер:
823.3 Кб
Скачать

6.5. Ссылки и ссылочные параметры

Во многих языках программирования имеются два способа обращения к функциям – вызов по значению и вызов по ссылке [1].

В С++ существуют три способа передачи аргументов в функции:

1) вызов по значению;

2) вызов по ссылке с аргументами ссылками;

3) вызов по ссылке с аргументами указателями.

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

#include <iostream>

using namespace std;

int squareByValue(int);

void squareByReference(int &);

int main(){

int x = 2, z = 4;

cout << "Before:" << endl;

cout << "x= " << x << endl;

cout << "z= " << z << endl;

squareByValue(x);

squareByReference(z);

cout << "After:" << endl;

cout << "x= " << x << endl;

cout << "z= " << z << endl;

return 0;

}

int squareByValue(int a){

return a *=a;}

void squareByReference(int &cRef){

cRef *=cRef;}

Рис. 6.15. Передача параметра по значению и по ссылке

Ссылочный параметр– это скрытый указатель, псевдоним соответствующего аргумента. Чтобы показать, что параметр функции передан по ссылке, после типа параметра в прототипе функции ставится символ амперсанда (&); такое же обозначение используется в списке типов параметров в заголовке функции. Например, объявлениеint &count в заголовке функции может читаться как «countявляется ссылкой наint». В вызове функции достаточно указать имя переменной, и она будет передана по ссылке. Тогда упоминание в теле вызываемой функции переменной по имени ее параметра в действительности является обращением к исходной переменной в вызывающей функции, и эта исходная переменная может быть изменена непосредственно вызываемой функцией (см. рис. 6.15.)

Ссылки можно также использовать как псевдонимы для других переменных внутри функций

int count = 1; //объявление целой переменной count

int &cRef = count; //создание cRef как псевдонима для count

++cRef;

Рис. 6.16. Создание ссылки внутри функции

Этот фрагмент дает приращение переменной count, используя ее псевдонимcRef. Ссылочные переменные должны получать начальные условия в их объявлениях. Как только ссылка объявляется как псевдоним другой переменной, все операции, выполняемые с псевдонимом (т.е. ссылкой), на самом деле будут выполняться с самой истинной переменной. Для псевдонима не резервируется никакого места в памяти.

Вызов функций по ссылке с аргументами указателями

Ранее было проведено сравнение и сопоставление вызовов по значению и по ссылке с аргументами ссылки. Сейчас рассмотрим на вызове по ссылке с аргументами указателями.

returnможно использовать для возвращения одного значения из вызываемой функции вызывающему оператору (или для передачи управления из вызываемой функции без возвращения какого-либо значения). Параметры могут быть переданы функции с использованием аргументов ссылок, чтобы дать возможность функции модифицировать исходные значения аргументов (таким образом, из функции может быть «возвращено» более одного значения), или чтобы передать функции большие объекты и избежать накладных расходов, сопутствующих передаче объектов вызовом по значению. Указатели, подобно ссылкам, тоже можно использовать для модификации одного или более значений переменных в вызывающем операторе, или передавать указатели на большие объекты данных, чтобы избежать накладных расходов, сопутствующих передаче объектов по значению.

В С++ программисты могут использовать указатели и операции косвенной адресации для моделирования вызова по ссылке. При вызове функции с аргументами, которые должны быть модифицированы, передаются их адреса. Это обычно сопровождается операцией адресации (&) переменной, которая должна быть модифицирована. Массивы не передаются с помощью&, потому что имя массива – это начальный адрес массива в памяти. При передаче функции адреса переменной может использоваться операция косвенной адресации (*) для модификации значения (если значение не объявлено какconst) ячейки в памяти вызывающего оператора.

На рис. 6.17 представлена программа с двумя вариантами функции, которая возводит в куб целое число – CubeByValue иCubeByReference. Первая функция передает переменнуюnumberфункцииCubeByValueвызовом по значению. ФункцияCubeByValueвозводит в куб свой аргумент и возвращает новое значение вmain, используя операторreturn. Новое значение присваивается переменнойnumberвmain. Ключевой момент вызова по значению состоит в том, что программисту предоставляется возможность анализировать результат вызова функции перед модификацией значения переменной. Например, в первой программе можно было бы сохранить результат, возвращаемыйCubeByValue в другой переменной, исследовать его значение, и после этого присвоить результат переменнойnumber.

Вторая функция передает переменную numberпо ссылке – в функциюCubeByReferenceпередается адресnumber. ФункцияCubeByReference в качестве аргумента получает nPtr(указатель наint). Функция разыменовывает указатель и возводит в куб значение, на которое указываетnPtr. Это изменяет значение number в main.

int CubeByValue (int);

void CubeByReference (int*);

int main(){

int number1;

int number2;

number1 = 5;

number2 = 5;

cout << "number1 before " << number1 << endl;

number1 = CubeByValue (number1);

cout << "number1 after " << number1 << endl;;

cout << "number2 before " << number2 << endl;

CubeByReference (&number2);

cout << "number2 after " << number2 << endl;

return 0;

}

int CubeByValue (int n){

return n*n*n;}

void CubeByReference (int* nPtr){

*nPtr = *nPtr **nPtr**nPtr;}

Рис. 6.17. Программа, иллюстрирующая передачу параметра по значению и по ссылке с аргументом указателем

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