Г. Шилтд - Самоучитель C++ (DJVU) (1114955), страница 20
Текст из файла (страница 20)
Более того, внутри функции компилятор автома- указатели и ссылки 129 Глава 4. Массивы, тически использует переменную, на которую указывает параметр-ссылка. Нет необходимости (и опять не допускается) ставить знак '. Таким образом, параметр-ссылка полностью автоматизирует механизм передачи параметра посредством вызова функции по ссылке. Важно понимать следующее: адрес, на который указывает ссылка, вы изменить не можете.
Например, если в предыдущей программе инструкция находилась бы внутри функции 10, ссылка и по-прежнему указывала бы на переменную 1 в функции тва!и(). Вместо инкрементирования адреса, на который указывает ссылка п, эта инструкция инкрементирует значение переменной (в данном случае это переменная 1). Параметры-ссылки имеют несколько преимуществ по сравнению с аналогичными (более или менее) альтернативными параметрами-указателями.
Во-первых, с практической точки зрения нет необходимости получать и передавать в функцию адрес аргумента. При использовании параметра- ссылки адрес передается автоматически. Во-вторых, по мнению многих программистов, параметры-ссылки предлагают более понятный и элегантный интерфейс„чем неуклюжий механизм указателей. В-третьих, как вы увидите в следующем разделе, при передаче объекта функции через ссылку копия объекта не создается.
Это уменьшает вероятность ошибок, связанных с построением копии аргумента и вызовом ее деструктора. 1. Классическим примером передачи аргументов по ссылке является функция, меняющая местами значения двух своих аргументов. В данном примере в функции аварагяао ссылки используются для того, чтобы поменять местами два ее целых аргумента: 111пс1ибе <ьовттевте> тяпа патпевраее вТпт ~оЫ выаратдв(1пт, ах, 1п1 ау1 1п1 ва1п ~ ) 1п1 1, 10; 3 =- 19т сопС « "1: " « 1 « еои1 « "з: " « 1 « "~п" 1 виара~да Ы, 3) 730 Самоучитель Су- сонг « "после перестановки: сонг « :1: " « 1 « ", :у соне « "з: " « 7' « "1п"у геснгп О; чоЫ Зууаракдв(1ПС 4Х, 1пг ау) уп Х у=су Если бы при написании функции аиарагуо вместо ссылок использовались указатели, то функция выглядела бы следующим образом: чо(с) зиарагдз(1пе *х, (п1 *у) ( *х = *уу у = Как видите, благодаря использованию ссылок в функции зиарагяз9, отпадает необходимость указывать знак *.
Ипс1ис(е <1озсгеагп> ((1пс1ис)е <сзлассу> изтпд паупезрасе зес)у чото коппс( (с(оиЫе зпслл) 1пг.улаьп ( ) лои)у1е 1 = 100.4у уос « 1 « уопс) (1 ); ис « 1 « "после округления н$ пп л = 10.9у сонс « 1 « коппс( ( 1 ) у сонс « 1 « "после округления "у "М*'у 2. В следующей программе с помощью функции гаап69 округляется значение типа с)овЫе. Округляемое значение передается по ссылке. Глава 4, ссылки 131 Массивы, указатели и гего гп 0; чотс( гоппс)(с)оиЬ1е впшп) ( ооыЬ1е бгас; босЫе ча1г разложение пога на целую и дробную части ггас = тпос)г (пплг, ача1); 1й(йгас < 0.5) пглл = уа1; е1зе гплл = уа1 ь 1.0г В функции гоппд() для разложения числа на целую и дробную части указана редко используемая функция пю(йО.
Возвращаемым значением этой функции является дробная часть; целая часть помещается в переменную, на которую указывает второй параметр функции гпос((О. 1. Напишите функцию пед(~, которая меняет знак своего целого параметра на противоположный. Напишите функцию двумя способами: первый — используя параметр-указатель и второй — параметр-ссылку, Составьте короткую программу для демонстрации обеих функций.
2. Что неправильно в следующей программе? // В этой программе есть ошибка 111пс1цс(е <1овггеагг> цв(пд пагпеарасе втс(; Уо(с( Егьр1е (с(ооЬ1е впогг) г )п( паап () с(ооЫе с( = 7. 0; ггтр1е ( ас)) соил « гег агп 0; // Утроение значения числа Уотс) гг1р1е(с)опЬ1е ати~т) )32 Само читель С++ ппгп = 3 * плтц 3. Перечислите преимущества параметров-ссылок. 4.7. Передача ссылок на обьекты Как вы узнали из главы 3, если объект передается функции по значению, то в функции создается его копия. Хотя конструктор копии не вызывается, при возвращении функцией своего значения вызывается деструктор копии.
Повторный вызов деструктора может привести в некоторых случаях к серьезным проблемам (например, при освобождении деструктором динамической памяти). Решает эту проблему передача объекта по ссылке. (Другое решение, о котором будет рассказано в главе 5, подразумевает использование конструктора копий.) При этом копия объекта не создается, и поэтому при возвращении функцией своего значения деструктор не вызывается.
Тем не менее, запомните: изменения объекта внутри функции влияют на исходный объект, указанный в качестве аргумента функции. Очень важно понимать, что ссылка не указатель, хотя она и указывает на адрес объекта. Поэтому при передаче объекта по ссылке для доступа к его членам используется оператор точка (.), а не стрелка (-)). 1. В следующем примере на экран выводится значение, передаваемое объекту по ссылке, но сначала рассмотрим версию программы, в которой объект типа итус1аззО передается в функцию Г0 по значению: $1пс1п<(е <ьояе теап> иягпд пюпеярасе ясй( с1аяя жус1аяя ( гпе мЬо; рпЫьс: ьаус1аяя(тпС и( [ иапо =и; сопя « "Работа конструктора " « нас « "М" ( 1ЭЭ Глава 4. Массивы, указатели н ссылки -тпус1ана() ( соий « "Работа деструктора " « н)чо « "1п"," ) 1ии Ы () ( теин и нас; о передается по значению чоЫ 1(тус1азз о) ( сои1 « "Получено" « о.
Ы() « "тп"; 1пи спа1п() пус1аан х(1); Х(х); текили О; Зте функция выводит не экран следую)дее: Работа конструктора 1 Получено 1 Работа деструктора 1 Работа деструктора 1 Как видите, деструктор вызывается дважды: первый раз, когда после выполнения функции Ц) удаляется копия объекта 1, а второй раз — по окончании программы. С другой стороны, если изменить программу так, чтобы использовать параметр- ссылку, то копия объекта не создается и поэтому после выполнения функции ('() деструктор не вызывается: ()1пс1ис(е <1озитеап~> па)пя пагиезрасе зим; с1азк гпус1азз ( )пг в)1о; риЬ11с: таус1азз (1пг.
и) н)чо = п; соил « "Работа конструктора " « нпо « "1п"; ) -вус1азз () ( сои « "Работа деструктора " « нЬо « "1п"; ) 1ии Ы ()» теииси нас; ) Теперь о передается по ссьлке чоЫ Х(тус1азз 4о) Самоучитель С-н- // отметьте, что по-прежнему используется оператор сепг « "Получено" « о. Ы() « "1п"; гп( ва1п () птус1аав х (1); ~(к) ) ге(пгп О; Эта версия предыдущей программы выводит на экран следующее: Работа конструктора ! Получено 1 Работа деструктора 1 Для доступа к членам обьекта по ссылке следует указывать оператор точка ('./, а не стрелка Г->).
1. Что неп)эавильно в следуюл(ей программео Покажите, как она может быть исправлена с помощью параметра-ссылки. // в этой програ>а'е есть отрубка ()1пс1пбе <1озехеа~п> () 1пс1п0е <с а Гг1пд> ()1пс1ис(е <са=а11Ь> па1по патеарасе зхс(; с1ааа аххсуре ( спаг *р; рцЬ11с: з1хеуре(спах'з); -зсхсуре() ( бе1есе [1 р) ) сваг 'де'.() ( гетигп р; ) ): асхсуре:: а1х1уре (с)тах *а) 1п(: 1; 735 Глава 4.
Массивы, указатели и ссылки 1 = в1г1еп(в) -+ 1; р = пест с11аг (1]; (Г(! р) ( соне « "С)либка выделения памяти~п") ехало (1)г вогсру(р, в); чей васи(в1ггуре х) сЬа- *в; в =х.дее (); сенс « в « "~п"т (п( гпаз.п () ( вт.гяуре а("Привет"), Ъ("Здесь")г в1юь (а); вЪои(Ъ)> гееигп О; 4.8. Ссылка в качестве возвращаемого значения Функции Функция может возвращать ссылку.
Как вы увидите в главе 6, возвращение ссылки может оказаться полезным при перегрузке операторов определенных типов. Кроме этого возвращение ссылки позволяет использовать функцию слева в инструкции присваивания. Зто приводит к важному и неожиданному результату. 1. Для начала, простая программа с функцией, которая возвращает ссылку: // Простой пример ссылки в качестве воеврвшвеьгото значения функции () гпс1пс1е <ьовггеапъ цз]пя пвтеврасе вгбг 136 Самоучитель 1пг ьш'(); 1пг х; )пг тпа)п () 1" 1) = 100; /l присваивание 100 ссылке, возвращаемой функцией 6(,' сонг «х « "М"; гегцгп 0; Возвращение ссылки на целое ыш йГ 11 1 гетцгп х; // возвращает ссылку на х Здесь функция Г0 объявляется возвращающей ссылку на целое. Внутри тела функции инструкция тетцтп х> не возвращает значение глобальной переменной х, она автоматически возвращает адрес переменной х (в виде ссылки).
Таким образом, внутри функции вта1пО инструкция )ОО; заносит значение 100 в переменную х, поскольку функция 1() уже возвратила ссылку на нее. Повторим, функция Го возвращает ссылку. Когда функция Г() указана слева в инструкции присваивания„то таким образом слева оказывается ссылка на объект, которую возвращает эта функция. Поскольку функция ГЦ возвращает ссылку на переменную х (в данном примере), то эта переменная х и получает значение 100.
2. Вам следует быть внимательными при возвращении ссылок, чтобы объект, на который вы ссылаетесь, не вышел из области видимости. Например, рассмотрим эту, слегка переделанную функцию Го: Возвращение ссылки на целое ).пь ьГ1] .-.пс х; // х — локальная переменная лееплп х; // возвращение ссылки на х В этом случае х становится локальной переменной функции Г() и выходит из области видимости после выполнения функции.