246071-Либерти-Освой-самостоятельно-С-за-21-день (852741), страница 40
Текст из файла (страница 40)
На самом же деле ссылкаrSomeRefпродолжаетдействоватькакпсевдонимпеременнойintOne,поэтомутакоеприсвоениеэквивалентноследующейоперации:intOne=intTwo;Это кажется достаточно убедительным, особенно при выводе на экран значенийпеременной intOne и ссылки rSomeRef (строки 19— 21): их значения совпадают со значениемпеременнойintTwo.Насамомделепривыводенаэкранадресоввстроках22—24вывидите,чтоссылкаrSomeRefпродолжаетссылатьсянапеременнуюintOne,аненапеременнуюintTwo.Не рекомендуется:Не пытайтесь переназначить ссылку.
Не путайте оператор адреса соператоромссылки.Рекомендуется:Используйтессылкидлясозданияпсевдонимовобъектов.Инициализируйтессылкиприобъявлении.НачтоможноссылатьсяСсылатьсяможноналюбойобъект,включаянестандартные(определенныепользователем)объекты. Обратите внимание, что ссылка создается на объект, а не на класс. Нельзя объявитьссылкутакимобразом:int&rIntRef=int;//неверноСсылку rIntRef нужно инициализировать, используя конкретную целочисленнуюпеременную,например:inthowBig=200:int&rIntRef=howBig;ТочнотакженельзяинициализироватьссылкуклассомCAT:CAT&rCatRef=CAT;//неверноСсылкуrCatRefнужноинициализировать,используяконкретныйобъектклассаCAT:CATfrisky;CAT&rCatRef=frisky;Ссылки на объекты используются точно так же, как сами объекты.
Доступ к даннымчленамиметодамосуществляетсяспомощьюобычногооператорадоступакчленамкласса(.),и, подобно встроенным типам, ссылка действует как псевдоним для объекта. Этот фактиллюстрируетсявлистинге9.4.Листинг9.4.Ссылкинаобъектыкласса1://Листинг9.4.2://Ссылкинаобъектыкласса3:4:#include<iostream.h>5:6:classSimpleCat7:{8:public:9:SimpleCat(intage,intweight);10:~SimpleCat(){}11:intGetAge(){returnitsAge;}12:intGetWeight(){returnitsWeight;}13:private:14:intitsAge;15:intitsWeight;16:}17:18:SimpleCat::SimpleCat(intage,intweight)19:{20:itsAge=age;21:itsWeight=weight;22:}23:24:intmain()25:{26:SimpleCatFnsky(5,3);27:SimpleCat&rCat=Fnsky;28:29:cout<<"Frisky:";30:cout<<Frisky.GetAge()<<"yearsold.\n";31:cout<<"ИFriskyвесит:";32:cout<<rCat.GetWeight()<<"kilograms.\n";33:return0;34:}Результат:Frisky:5yearsold.ИFriskyвесит:3kilograms.Анализ:Встроке26объявляетсяпеременнаяFriskyвкачествеобъектаклассаSimplcCat.Встроке 27 объявляется ссылка rCat на некоторый объект класса SimpleCat, и эта ссылкаинициализируется с использованием уже объявленного объекта Frisky.
В строках 30 и 32вызываютсяметодыдоступакчленамклассаSimpleCat,причемсначалаэтоделаетсяспомощьюобъектаклассаSimpleCat(Frisky),азатемспомощьюссылкинаобъектклассаSimpleCat(rCat).Обратите внимание, что результаты идентичны. Снова повторюсь: ссылка — это всего лишьпсевдонимреальногообъекта.ОбъявлениессылокСсылкаобъявляетсяпутемуказаниятипаданных,закоторымследуетоператорссылки(&)иимяссылки.Ссылкинужноинициализироватьприобъявлении.Пример1:inthisAge;int&rAge=hisAge;Пример2:CATboots;CAT&rCatRef=boots;НулевыеуказателиинулевыессылкиКогдауказателинеинициализированыиликогдаониосвобождены,имследуетприсваиватьнулевоезначение(0).Этонекасаетсяссылок.Насамомделессылканеможетбытьнулевой,ипрограмма, содержащая ссылку на нулевой объект, считается некорректной.
Во время работынекорректнойпрограммыможетслучитьсявсечтоугодно.Онаможетвнешневестисебявполнепристойно,ноприэтомудалитвсефайлынавашемдискеиливыкинетещекакой-нибудьфокус.Большинство компиляторов могут поддерживать нулевой объект, ничего не сообщая поэтому поводу до тех пор, пока вы не попытаетесь каким-то образом использовать этот объект.Однако не советую пользоваться поблажками компилятора, поскольку они могут дорого вамобойтисьвовремявыполненияпрограммы.ПередачааргументовфункцийкакссылокНазанятии5выузналиотом,чтофункцииимеютдваограничения:аргументыпередаютсякак значения и теряют связь с исходными данными, а возвращать функция может только однозначение.Преодолетьэтидваограниченияможнопутемпередачифункцииаргументовкакссылок.ВязыкеC++передачаданныхкакссылокосуществляетсядвумяспособами:спомощьюуказателейи с помощью ссылок.
Не запутайтесь в терминах: вы можете передать аргумент как ссылку,используялибоуказатель,либоссылку.Несмотря на то что синтаксис использования указателя отличается от синтаксисаиспользования ссылки, конечный эффект одинаков. Вместо копии, создаваемой в пределахобластивидимостифункции,вфункциюпередаетсяреальныйисходныйобъект.Назанятии5выузнали,чтопараметры,передаваемыефункции,помешаютсявстек.Еслифункциипередаетсязначениекакссылка(спомощьюлибоуказателей,либоссылок),товстекпомещаетсянесамобъект,аегоадрес.Вдействительностивнекоторыхкомпьютерахадресхранитсявспециальномрегистре,австекничегонепомещается.Влюбомслучаекомпиляторуизвестно,какдобратьсядоисходногообъекта, и при необходимости все изменения производятся прямо над объектом, а не над еговременнойкопией.При передаче объекта как ссылки функция может изменять объект, просто ссылаясь нанего.Вспомните,чтовлистинге5.5(см.Занятие5)демонстрировалось,чтопослеобращениякфункции swap() значения в вызывающей функции не изменялись.
Исключительно ради вашегоудобстваэтотлистингвоспроизведенздесьещераз(листинг9.5).Листинг9.5.Демонстрацияпередачипозначению1://Листинг9.5.Передачапараметровкакзначений2:3:#include<iostrearn.h>4:5:voidswap(intx,intу);6:7:intmain()8:{9:intx=5,у=10;10:11:cout<<"Main.Beforeswap,x:"<<x<<"у:"<<у<<"\n";12:swap(x,у);13:cout<<"Main.Afterswap,x:"<<x<<"у:"<<у<<"\n";14:return0;15:}16:17:voidswap(intx,intу);18:{19:inttemp;20:21:cout<<"Swap.Afterswap,x;"<<x<<"у:"<<у<<"\n";22:23:temp=x;24:x=у;25:у=temp;26:27:cout<<"Swap.Beforeswap,x:"<<x<<"у:"<<у<<"\n";28:29:}Результат:Main.Beforeswap,x:5у:10Swap.Beforeswap,x:5у:10Swap.Afterswap,x:10у:5Main.Afterswap,x:5у:10Эта программа инициализирует две переменные в функции main(), а затем передает ихфункцииswap(),которая,казалосьбы,должнапоменятьихзначения.Однакопослеповторнойпроверкиэтихпеременныхвфункцииmain()оказывается,чтоонинеизменились.Проблемаздесьвтом,чтопеременныеxиупередаютсяфункцииswap()позначению,т.е.вданном случае локальные копии этих переменных создаются прямо в функции.
Чтобы решитьпроблему,нужнопередатьзначенияпеременныхxиукакссылки,В языке C++ существует два способа решения этой проблемы: можно сделать параметрыфункцииswap()указателяминаисходныезначенияилипередатьссылкинаисходныезначения.Передачауказателейвфункциюswap()Передавая указатель, мы передаем адрес объекта, а следовательно, функция можетманипулировать значением, находящимся по этому переданному адресу. Чтобы заставитьфункцию swap() изменить реальные значения с помощью указателей, ее нужно объявить так,чтобыонапринималадвауказателянацелыезначения.Затемпутемразыменованияуказателейзначенияпеременныхxиубудутнасамомделеменятьсяместами.Этаидеядемонстрируетсявлистинге9.6.Листинг9.6.Передачааргументовкакссылокспомощьюуказателей1://Листинг9.6.Примерпередечиаргументовкакссылок2:3:#include<iostream.h>4:5:voidswap(int*x,int*y)6:7:intmain()8:{9:intx=5,у=10;10:11:cout<<"Main.Beforeswap,x:"<<x<<"у:"<<у<<"\n";12:swap(&x,&y);13:cout<<"Main.Afterswap,x:"<<x<<"у:"<<у<<"\n";14:return0;15:}16:17:voidswap(int*px,int*py)18:{19:inttemp;20:21:cout<<"Swap.Beforeswap,*рх:"<<*px<<"*py:"<<*py<<"\n";22:23:temp=*px;24:*px=*py;25:*py=temp;26:27:cout<<"Swap.Afterswap,*px:"<<*px<<"*py:"<<*py<<"\n";28:29:}Результат:Main.Beforeswap,x:5y:10Swap.Beforeswap,*px:5*py:10Swap.Afterswap,*px:10*py:5Main.Afterswap,x:10y:5Анализ: Получилось! В строке 5 изменен прототип функции swap() где в качествепараметров объявляются указатели на значения типа int, а не сами переменные типа int.
Привызовевстроке12функцииswap()вкачествепараметровпередаютсяадресапеременныхxиу.Встроке19объявляетсялокальнаядляфункцииswap()переменнаяtemp,которойвовсенеобязательнобытьуказателем:онабудетпростохранитьзначение*px(т.е.значениепеременнойxв вызывающей функции) в течение жизни функции. После окончания работы функциипеременнаяtempбольшененужна.Встроке23переменнойtempприсваиваетсязначение,хранящеесяпоадресуpx.Встроке24значение,хранящеесяпоадресуpx,записываетсявячейкусадресомpy.Встроке25значение,оставленное на время в переменной temp (т.е. исходное значение, хранящееся по адресу px),помещаетсявячейкусадресомpy.В результате значения переменных вызывающей функции, адреса которых были переданыфункцииswap(),успешнопоменялисьместами.Передачассылоквфункциюswap()Приведенная выше программа, конечно же, работает, но синтаксис функции swap()несколько громоздок.