[БЕЗ_ЗВУКА] В
предыдущем видео мы с вами говорили, что параметры функции передаются по значению,
то есть копируются внутрь функции.
И изменяя локальные, формальные параметры функции,
мы не можем изменить фактические параметры, то есть те объекты,
которые были переданы в функцию в месте ее вызова.
Но что же нам делать, если нам именно это и нужно,
если нам нужно поменять те объекты, которые функцию передали?
Давайте рассмотрим пример.
Напишем функцию Swap, которая обменивает
значения двух переменных.
Выводим Swap, две переменные — x, y, и,
собственно, int — временная переменная.
Сохраняем значение x, в x записываем y и в y
записываем значение временной переменной.
Давайте посмотрим, как эта функция работает в ее текущем виде.
Объявим переменную a = 1, переменную b = 2,
выполним функцию Swap и выведем
сообщение: a = a,
перевод строки,
и b = b.
Вот видя вот такой вот вызов и не зная,
как функция Swap реализована внутри, мы будем ожидать,
что a станет равным 2,
а b станет равным 1.
Скомпилируем нашу программу, запустим ее и увидим,
что она вывела a = 1, а b = 2, собственно,
потому что параметры x и y были скопированы внутрь
Swap и их модификация никак не затронула переменные a и b.
Собственно, вопрос: а что нам сделать, чтобы правильно написать функцию Swap?
И выход есть.
Для этого переменные x и y должны быть не типа int, а ссылка на int.
Передавать параметры функции Swap надо по ссылке.
Ссылка — это особый тип языка C++,
которая является синонимом переданного в нее объекта,
и, как видите, она оформляется с помощью знака амперсанда,
который идет после типа, справа от, в данном случае, int.
Добавив два знака амперсанда для переменной x и для переменной y,
я могу запустить нашу программу, скомпилировать нашу программу снова,
запустить, и мы видим, что теперь она работает так, как мы ожидали.
Переменная a стала равна 2, а переменная b стала равна 1.
То есть значения переменных действительно поменялись,
и функция Swap действительно поменяла те переменные,
которые были в нее переданы.
Таким образом, вы должны теперь запомнить,
что для модификации объектов,
которые передаются в функцию, их нужно передавать в функцию по ссылке.
Ну, а ссылка оформляется с помощью знака амперсанда.
Давайте рассмотрим другой пример,
в котором использование ссылок окажется очень полезным.
Давайте вспомним, что мы говорили,
что в библиотеке algorithm есть специальный алгоритм сортировки.
Давайте я вам напомню, как это делается.
У нас есть вектор целых чисел,
заполненный какими-то значениями.
И чтобы его отсортировать, мы должны написать sort (begin
(nums), end (nums)).
И давайте выведем содержимое вектора,
чтобы убедиться, что у нас все правильно.
Компилируем, запускаем и видим,
что наш вектор отсортировался, все работает.
Какой есть недостаток у данного вызова sort?
Недостаток заключается в том, что имя вектора, nums, мы используем дважды.
Соответственно, когда мы набираем этот код, мы можем опечататься,
допустить какую-то ошибку,
и из-за этого у нас программа в лучшем случае не скомпилируется,
а на самом деле иногда может и неправильно работать.
И поэтому мы хотели бы написать такую функцию сортировки,
которая позволяла бы использовать имя вектора только один раз.
Ну, как бы мы ее написали, не зная про ссылки?
Мы бы, наверное, написали бы ее вот так.
Мы бы написали функцию, которая возвращает вектор int и принимает вектор <int> v.
Внутри бы она, собственно, выполняла бы вызов sort,
и, после того как она его отсортировала, она бы его возвращала.
Давайте вызовем
нашу функцию sort, скомпилируем нашу программу.
Все у нас компилируется,
работает, и также у нас вектор получается сортированным.
Но мы не решили нашу проблему.
Мы в месте вызова sort продолжаем использовать имя nums дважды,
первый раз — передавая параметр, и второй раз — принимая значения.
Кроме того, если мы посмотрим на саму функцию sort,
то в ней тип вектора также указан дважды.
Первый раз в качестве параметра и второй раз в качестве типа
возвращаемого значения.
У нас опять есть дублирование.
Дублирование кода, как мы все знаем, это плохо, и от него надо избавляться.
И вот чтобы такого не было, не было дублирования, нам очень помогут ссылки.
Давайте перепишем нашу функцию sort,
чтобы у нее тип возвращаемого значения был в void, а вектор примем по ссылке.
return нам тогда становится не нужен,
и в месте вызова мы,
наконец, добились того, к чему стремились.
Мы один раз указываем вектор.
Наша программа продолжает работать, и теперь мы
говорим: отсортируй нам, пожалуйста, вектор nums, и указываем его один раз.
Таким образом, мы смогли избежать дублирования кода,
передавая вектор по ссылке.
Подведем итоги.
Если вам в вашей функции нужно модифицировать те объекты, которые
в эту функцию переданы в месте вызова, то принимать такие параметры нужно по ссылке.
При этом вы теперь знаете,
что для объявления ссылки нужно поставить знак амперсанда справа от типа параметра.