Г. Шилдт - Полный справочник по C++ (1109478), страница 66
Текст из файла (страница 66)
При вызове функции эти параметры копируются и присваиваются соответствующим аргумснтал(. Как всегда, указатель е)г1в ссылается на объект, геисрирузоший вызов операторной Функции (в дашюм примере ца объект о), Расом<прим пример перегруженного оператора "()" в классе 1ое. Он присваивает зпачеоия двух своих аргументов членам объекта класса 1ос, в которых хранится значспис широты и лолготы.
)Ф(по1пйе <1овт сеаи> пвъпд паиеврасе вой," с1авв ).оо ( 1пе 1оп01епйе, 1ае1сийе; рпЫ1с: (ос() () ') оо (1 ." 1о, (пс 1С) ( )опцтепйе = 1а; 1ас1спйе — 1с; ) уо ай в)зои ( ) соцс «1опд1спйе « сове « 1аейспйе « '*1п"; ) Часть ((. Язык С++ 1ос орехасох+(1ос ар2); 1ос орехахох()[тпс 1, ьпс 2); // Перегруженный оператор ( ) лля класса 1ос. 1ос 1ос;:орехасох()(упс 1, 1лс з) ( 1опдххппе = зп 1асзсие)е хеспхп яснье.
) // Перегруженный оператор + лля класса 1ос. 1ос 1ос::орехахох+(1ос ор2) ( 1ос Сеир; хежр.1опдгсие)е = ор2.1олд1хпх)е + 1опд1спе)е; петр. 1ас1спсе = ор2. 1асьсисе е 1асьспое; хехихп петр; ) ьпх жаьп() ( 1ос оЬ1(10, 20), оЬ2(1, 1); оЬ1.внои(); оЬ1(7, 8); // Оператор применяется самостоятельно оЬ1,еноы(); оЬ1 = оЬ2 + оЬ1(10, 10); // Оператор можно использовать // внутри выражений оЬ1.анси(); хехихп 0: Зга программа выволит на экран такие строки.
10 20 7 а 11 11 Помните, что, перегружая оператор "()", вы можете использовать любой тип параметров и любой тнп возвращаемого значения. Эти типы можно выбирать в зависимости от конкретного приложения. Кроме того, можно предусматривать значения аргумс~ ~тов по умолчанию. Перегрузка оператора н->и Оператор ссылки «а член обьекгна (с)азз гпсгпйег ассезз орега(ог) при перегрузке считается унарным. Его общий аил таков. й обьект -> элеменгя Глава 15. Перегрузка операторов Операторная функция, персгружающая оператор "->", вызывается из обпекта.
Функция орегаеог->О должна возвращать указатель на объект класса, для которого он определен. Элазма должен быть членом, доступным внутри объекта. Следующая программа иллюстрирует перегрузку оператора "->*' и демонстрирует эквивалентность выражений оЬ.1 и оЬ->1, когда операторная функция орегаеог-> () возвращает указатель еь1в. $1пс1цг)е <1авсгеаю> цв1пд паюеврасе вссб с1авв п1ус1авв ( рцЬ11с: зпс 1; юус)авв "орегапог->() (геецгп СЬ1в;) 1гс тазп() тус)авв сЬ; оЬ->1 = 10; У/ Эквивалентно выражению сЬ.1 сове « оЬ.1 « " "' « оЬ->1; гесцгп О; ) Операторная функция орегаеож->() должна быть членом класса, для которого она определяется.
Й~ Перегрузка оператора "," Язык С++ допускает перегрузку оператора "", ". Этот оператор является бинарным. Его смысл при перегрузке может быть произвольным. Однако, если целью перегрузки является выполнение операции, аналогичной стандартной, следует игнорировать все аргументы. кроме крайнего справа. Именно этот параметр считается результатом стандартного оператора ", ".
Рассмотрим программу, демонстрирующую перегрузку оператора ". ". $1пс1цг)е <1овсгевзп> овьпд паюеврасе вМ; с1авв 1ос ( 1пп 1опд1еиг)е, 1ае1еиг)е; рцЬ11с: 1ос() () 1ос(1ге 1д, 1ге 1С) 1опд1ецг)е = 1д; 1ае)евое)е = 1С; ) уо1г) виси() ( соос «1опд1сиг)е « соса «1ас1сос)е « "Ы"; Часть П. Язык С++ 1ос орелааот+(1ос ор2); 1ос оретатот,(1ос ор2); // перегрузка оператора "запятая'* для класса 1ос 1ос 1ос.":оретатот,(1ос ор2) ( 1ос сегярг Сетр.1опд1кнг?е = ар2.1опд1спг(е; Севр.1акакпде = ор2.1акааиде; соис «ор2. 1опдаснде « *' " «ор2.1асаспйе « "тг1"; теситп се?кр; ) перегрузка оператора + для класса 1ос 1ос 1ос::оретасот+(1ос ор2) < 1ос веер? Секр.1опдапиде = ор2.1опдзапде + 1опд?пабе; оетр.1ак?кобе = ор2.1аг1Сийе + 1ак?сиг?е; тексен Сверг ) апт ыатп() ( 1ос оЬ1(10, 20), оЬ2( 5, ЗО), оЬЗ(1, 1); оЬ1.вдов(); ОЬ2.знои()? оЬЗ.вдов(); свис « "М" ' оЬ1 = (оЬ1, оЬ2+оЬ2, оЬЗ); оЬ1.вдов()г // Выводит на экран числа 1 1, // т.е.
значение объекта оЬЗ тесихп О; ) Зта программа выводит на экран следующие строки. 10 20 5 ЗО 1 1 10 60 1 1 1 1 Глава 16. Перегрузка операторов Несмотря на то что все операнды, стоящие в левой части, игнорируются, каждое выражение по-прежнему вычисляется компилятором, поэтому возможны все предусмотренные побочные эффекты. Слелуст помнить, что операнд, стоящий в левой части, передается с помощью указателя еиав, а его значение игнорируется функцией ореевеее, [Н Функция возвращает значение операнда, стоящего в правой части. Таким образом, действия перегруженного оператора "," напоминщот стандартные.
Если вы хотите, чтобы оператор выполнял другие операции, следует изменить эти свойства. Часть Я. Язык С++ аслсдование — один из краеугольных камней объектно-ориентированного про- Н граммировапия, так как оно позволяет создавать иерархические классификации. Используя наследование, можзю создавать обшие классы, опрелеляюшие свойства, характерные для всей совокупззопи родственных классов. Эти классы могуг наслеловат» свойства друг у друга, добаюия к ним свои собственные уникальные характеристики. Согласно стандартной термиззологии языка С++ класс, лежащий в основе иерархии, называется базовым (Ьазе с)азз), а класс, наследуюший свойства базового класса, — щзоизездным (депчед с1аза).
Производные классы, в свою очередь, могут бьггь базовыми по отношению к другим классам. В языке С++ предусмотрен мощный и гибкий механизм наследования. Первичные сведения о наследовании содержатся в главе 11. Настало время изучить его подробнее. ~з управление доступом к членам базового класса При наследовании члены базового класса становятся членами производного класса. Как правило, для наследования используется следуюшая синтаксическая конструкция.
| с1авв иия-ироизводиого-класса зуровеии доступа илгя-базового-класса ( l / тело класса ); Параметр уровень достула определяет статус членов базового класса в производном классе. В качестве этого параметра используются спецификаторы рцЬ11а, рхдчеее или рхоееоеее. Если уровень доступа не указан, то для производного класса по умолчанию используется спецификатор рх1чеее, а лля производной структуры— риь11а. Рассмотрим варианты, возникаюшие в этих ситуациях.
(спецификатор рхоееаеезт будет описан в следуюшем разделе.) Если уровень доступа к членам базового класса задается спецификатором риЬ11с, то все открытые и зашишенные члены базового класса становятся открытыми и зашишенными членами производного класса. При этом закрытые члены базового класса не меняют своего статуса и остаются недоступными членам производного.
Как демонстрирует следующая программа, объекты класса аехдчеа могут непосредственно ссылаться на открытыс члены класса Ьеее. Ф1пс1цде <(оветеаиз> пвдпд палзеврасе всдз с1авв Ьаве зпе з., )з рцЬ11с: чохд вес((пс а, хпс Ь) ( к=аз З=Ьз чоЫ впои() ( попс « з « " " « 1 « "1п"з ) )з с1евв деххчед : рцЬ11с Ьаве ( ъпс 1<; рцЬ1 з.с: дехзчед((пс х) [ К=хз чоЫ вноиК(! ( соцс « К « "зп"з )з Часть П. Язык С++ )ззс шаз.п() ( дес1иед оЬ(3)з оЬ.вес(1„ 2); // Обращение к члену класса Ьаве оЬ.пном()з // Обращение к члену класса Ьаве оЬ.вноый()з // Обрашение к члену класса детфиед сесисц Оз ) Если свойства базового класса наследуются с помощью спецификатора доступа ртьззаее, все открытые и защищенные члены базового класса становятся закрытыми членами производного класса.
Например, следующая программа даже ззс будет скомпилирована, так как обе функции вес() и аЬом() теперь являются закрытыми членами класса дет1чед. // Эта программа не будет скомпилировала. ВЫс1иде <1овгтеаш> ивЫО пашеврасе всдз с1авв Ьаве ( 1пс 1, риЬ1зсз чоЫ вес(1пе а, ЫС Ь) ( з=а; 3=Ьз ) иоЫ вбом() ( соме « з « " ' « 3 « "1п // Открытые члены класса Ьаве являются // закрытыми членами класса делфиед. с1авв дет1чед: рльиаее Ьаве зпс уы риЬ11с: дет1иед(1пг х) ( й=хз ) иоЫ вцомх() ( соле « )с « '1п"з ) ): Ыс шаьп(] ( дехьчед оЬ(3)з оЬ.вее[1, 2)з // Ошибка, доступ к функции вес() вапрешен. оЬ.вбом()з // Ошибка, доступ к функции вьем() вапрешен.
лесисп Оз ) Г/ри закрьтюм нвследоввма всв открытие и звщищенныв члены базового класса спшновяпзся закрытыми езвнвми производного кпгссв. Это значит, что они оствкзлся досеулньзии членам производного класса, но недоступны остальным злементвм зззограимы, не явпятщомся членами базового ипи производного классов. И Наследование и защищенные члены Спецификатор рхоеесеед повышает гибкость механизма наследования. Если член класса объявлен защищенным (рго(ес(ед), то вне класса он недоступен. С атой точки зрения защищенный член класса ничем не отличается от закрытого. Единственное Глава )б. Наследование исключение из этого правила касается иаследоваз(ия.
В этой ситуации зашишенный член класса существенно отличается от закрытого. Как указывалось в предылушем разделе, закрытыи член базового класса не поступен лругим элементам програмлсы, включая производный класс. Однако зашишенпыс члены базового класса ведут себя иначе. При открытом наследовании защищенные члены базового класса ствззовятся зашишснными членами производного класса и, следователыю, доступны остальным членам производного класса. Ииыми словами, зашишснные члены класса по отношению к своему классу являются закрытыми и.
в то жс время, могут наследоваться производным классом. Рассмотрим пример. В пс1нс(е сзоясхеазэ> чв1дд пвзаеврасе ясс)з с1авя Ьвве ( рхохессес(з 1ззх з, Эз // закрыты по отношения к классу Ьаяе // но доступны классу с)ех1чес). риыдзсз чоз.з) яее(1пе а, 1пе Ь) ( 1=а; Э=Ьз ) чо1с) япоиО ( свих « 1 « '* " « 3 « " 1д'з ) )з с1ввв с(ех1чес), риЬ11с Ьеве 1дс ):з рнЬ1з.оз // Класс дех1чес) имеет доступ к членам 1 и э ия класса Ьаве чо1с( вее)сО ( )с=1*зз ) чо1с) яцоиК() ( соос « К « "1п"з зязх та1п О ( с)ех1чес( оЬз оЬ.яее(2, 3)з // Все в порядке, этот член доступен классу с(ех1чес) оЬ.знои()з // Все в порядке, этот член доступен классу с)ех1чео оЬ.вея)с()з оЬ.внои)сО з хехихп оз ) В данном примере, поскольку класс пехдчед наследует свойства класса ьеве с помощью открытого наследования, а переменные 1. н 3 объявлены зазцишенпыми, функция яее)с() из кчасса стех1чест имеет к ним доступ.
Если бы переменные 1 и 3 были объявлены в классе Ьеве закрытыми, то класс стех1чеа не имел бы к ним доступа, и программу нельзя было скомпилировать. Если произвсаный класс является базовым по отношению к другому производному классу, то любой зашишенный член исходно~о базового класса, открыто наследуемый первым производным классом, также может наследоваться вторым производным классом как зашишенный член. Например, следуюшая программа вполне корректна, И КЛаСС стехдчепд дЕйСтВИтЕЛЬНО ИМЕЕТ дсетун К ПЕРЕМЕННЫМ 1 И ~. ()1пс1ис)е сйовехеаэ> ив1дя пвязеярасе яес(з Часть П, Язык С++ с1авв Ьаве ( ргосесседз ?пг з., риЫ?с з тозд вес [1пь а, ?пс Ь] ( ?=аз )=Ь; ) ъозд вЬои() ( соис «1 « " " « 1 « "?и" з )з // Переменные 1 и 1 наслепуптсв как ваыишенные с1авв дег?ззед1 : риЫ?с Ьаве ( 1г/с ?и риЫзс з ъо)д ве?К() ( К = 1*1 з ] // ?еяа? иа?д впоии[) ( свис « К « 'хп"; ); // 1 апд > 1ппег1еед ?пд?гесг?у ГЬгоияЬ дег?иед1. с1авв дег?иед2 : риЬ1?с дег?ззед1 ( хп? пз риЫ1с з ззо?д веепзО ( и = 1-бз ) // Допускается ио?д вцике() ( соис « ж « "тп"з ) )з 1пе зла?п () ( дег?иед1 оЬ1/ дег?иед2 оЬ2/ оЬ1.вес[2, 3)з ОЫ.
впои[) з оЫ.веСК[) з оЬ1.виоид[)з оЬ2 вес[3, 4)з оЬ2.впои()з оЬ2.веси()з оЬ2.весаз()з оЬ2.впоик(]з оЬ2.виоилз()з гесигп Оз Однако, если бы к классу Ьаве применялся механизм закрытого наслелования. то все его члены стали бы закрытыми членами класса дек1ззед1 и были недоступньз классу дет1еед2. (В то же время переменные 1 и 3 были бы по-прежнему доступны классу дет1еед1.) эта ситуация иллюстрируется следующей программой (озза содержит ошибку и не компилируется). // Эта программа содерзп<т описку. $?пс1иде <зовегеаив ив1пд паееврасе ведз с1авв Ьаве РГОСЕСЕЕдз ?пе з., Глава (б.