По умолчанию С и С++ передает аргументы в функцию, используя передачу по значению. Это означает, что функция использует копии аргументов, благодаря чему предотвращается возможность модификации аргументов функции. Если требуется предоставить функции возможность изменять значения своих переменных-аргументов, то в языке С параметры должны быть объявлены явным образом как указатели. Тогда функция будет обрабатывать значения вызванных переменных, используя оператор *. Например, следующая программа реализует функцию swap(), обменивающую между собой значения двух аргументов целого типа:
#include <iostream.h>
void swap(int *a, int *b);
int main ()
{
int x, y;
x = 99;
у = 88;
cout << x << " " << у << "\n";
swap(&x, &y); // обмен значений
cout << x << " " << у << "\n";
return 0;
}
// версия swap(), явно использующая указатели
void swap (int *a, int *b)
{
int t;
t = *a;
*a = *b;
*b = t;
}
При вызове функции swap() перед подставляемыми в нее переменными должен стоять оператор взятия адреса &. Именно так реализуется передача по ссылке в С. Хотя С++ позволяет подобный синтаксис, он поддерживает и более ясный, более прозрачный метод передачи по ссылке, используя параметр типа ссылки (reference parameter).
В С++ можно создавать передаваемые по ссылке параметры. Для этого при объявлении функции перед параметром ставится знак амперсанта &. В качестве примера рассмотрим функцию:
void f(int &f)
{
f = rand(); // изменяет переданный аргумент
}
Обратим внимание, что инструкция
f = rand();
не использует оператор *. При объявлении параметра-ссылки компилятор С++ знает, что это неявный указатель, и обрабатывает его соответствующим образом. Всякий раз при вызове функции f() ей автоматически передается адрес аргументов. Например, в следующем фрагменте кода
int val;
f (val); // получает случайное значение
printf("%d", val);
адрес переменной val, а не значение этой переменной, передается функции f(). Благодаря этому функция f() может модифицировать значение переменной val. Обратим внимание, что при вызове функции f() нет необходимости ставить оператор взятия адреса & перед переменной val. Компилятор автоматически передает функции адрес переменной val.
Для того, чтобы проиллюстрировать использование параметров ссылочного типа, мы перепишем функцию swap() с использованием ссылок. Обратим внимание, каким образом функция swap() объявляется и вызывается:
#include <iostream.h>
void swap (int &a, int &b); // объявление в виде ссылок
int main()
{
int x, у;
x = 99;
у = 88;
cout << х << " " << у << "\n";
swap(x, у); // обмен значений
cout << х << " " << у << " \n";
return 0;
}
/* swap () определена с использованием передачи по ссылке, а не по значению */
void swap (int &а, int &b)
{
int t;
t = a;
a = b; // установка значения x
b = t; // установка значения у
}
Еще раз отметим, что определив а и b как параметры ссылочного типа, мы не нуждаемся в использовании оператора взятия адреса & при вызове функции swap(), а также не используем оператор * внутри функции swap(). На применение переменных ссылочного типа имеется ряд ограничений:
- Нельзя взять ссылку от переменной ссылочного типа, иными словами, нельзя взять ее адрес.
- Нельзя создать массив ссылок.
- Нельзя создать указатель на ссылку.
- Ссылки на битовые поля не допускаются.