Передача по значению и по ссылке
В этом уроке вы узнаете, как функция может изменить переменную вызывающего кода и как передать в функцию большой вектор, не копируя его целиком. И то и другое делают ссылки. Во второй части урока вы познакомитесь с указателями: они работают с адресами переменных в памяти, и вы будете встречать их во многих программах и библиотеках на C++.
Сначала вспомните, что происходит при вызове функции. Значение аргумента копируется в параметр. Параметр — новая локальная переменная, поэтому, когда функция меняет его, она меняет только свою копию:
#include <iostream>
void addPoint(int points) {
points = points + 1;
std::cout << "В функции: " << points << std::endl;
}
int main() {
int score = 10;
addPoint(score);
std::cout << "В main: " << score << std::endl;
return 0;
}Эта программа выводит:
В функции: 11
В main: 10Это называется передачей по значению: функция получила только значение 10, а не переменную score. С вектором в уроке «Функции» было так же: функция получила его копию. Чаще всего это хорошо, потому что функция не может случайно изменить ваши переменные.
Но если вы хотите, чтобы функция изменила переменную, напишите знак & после типа параметра:
#include <iostream>
void addPoint(int& points) {
points = points + 1;
}
int main() {
int score = 10;
addPoint(score);
addPoint(score);
std::cout << "Очки: " << score << std::endl;
return 0;
}Эта программа выводит:
Очки: 12Параметр int& points — это ссылка на int. Ссылка — не копия: это ещё одно имя переменной, которую вы передаёте в функцию. В вызове addPoint(score) параметр points внутри функции — просто другое имя для score, поэтому всё, что функция делает с points, происходит со score. Это называется передачей по ссылке.
Вызов выглядит так же, как раньше. О том, что функция может изменить вашу переменную, говорит только & в первой строке функции. Пробелы вокруг & не важны: int& points и int &points значат одно и то же. На этом курсе & пишут сразу после типа.
Остерегайтесь таких ошибок:
- Если забыть
&, программа всё равно компилируется и запускается, но переменная не меняется, и никакой ошибки нет. Когда функция «ничего не делает», сначала проверьте&. - Параметру-ссылке нужна переменная. Вызов
addPoint(5)заканчивается ошибкойno matching function for call to 'addPoint'(нет функции, подходящей под вызов) и примечаниемcandidate function not viable: expects an lvalue for 1st argument. Слово lvalue означает примерно «то, чему можно присвоить значение», например переменную. Число5— не переменная, которую функция могла бы изменить.
Задание
- 1
Программа выводит
Деньги: 50, потому что функцияdoubleItудваивает только свою копию. Сделайте её параметр ссылкой, чтобы функция удваивала переменнуюmoney. Тогда программа выведетДеньги: 100. - 2
Под функцией
doubleItнапишите функциюspendс двумя параметрами: ссылкойmoneyтипаint&и суммойamountтипаint. Функция вычитает сумму из денег. В концеmain(передreturn 0;) вызовитеspend(money, 30)и под ним выведите деньги так же, как выше. Программа выведетДеньги: 100, а затемДеньги: 70.