Г. Шилдт - Полный справочник по C++ (1109478), страница 52
Текст из файла (страница 52)
Дружественная функция может быть членом другого класса. Рассмотрил» вариант нашей программы, включив функцию ЕЕ1е() в класс с1. ()1пс1пде <Ьовстеат> пвьпя паа»еврасе всбг сопвс 1пе 1ВЬЕ = О; сопят Ьпе тъ»ПЭЕ = 1» с1авв С2» // Неполное объявление с1авв С1 1ПС веа»пвг // Равно 1ПЬЕ, если экран занят, // и ХЖЖЕ, если свободен. с1авв С2 ( Ьпс всатпв // Равно ХИЛЬЕ, если экран занят, // и 1Ь»ОБЕ, если свободен. // риЫЬс: чойб все веабпв(1пе веаее)г » гьепб Ьпе С1::1б1е(С2 Ы г )г чойб С1»» вес веаспв (1пе в Сабе) ( всасив - "всасег чо1б С2::все всасив(тпс всасе) ( всасив = зевсе; ) Часть П.
Язык С++ // риЫ(с» чоьб вес веаспв Ьпс ЬН1е(С2 Ы г )г (Ьпс всаее)» // Теперь функция 1б1е() †чл класса С1. /У Функция 161е() является членом класса С1 и другом класса С2 Тп» С1::ъб1е(С2 Ь) ( Тт(в»а»ив )) Ь.в»а»ив) ге»итп О; е1ве хе»итп 1; ) тп» ва5п() ( С1 х; С2 у; х.ве» в»а»ив(1ЦПЕ); у.ве» в»а»ив(1ПГЕ); 1»(х.ъб1е(у)] сои» « "Экран свободен.1п"; е1ве сои» « 'Экран занят.
1п"; х.ве» в»а»ив(1НПБЕ); 1»(х.Ы1е[у)) сои» « "Экран свободен.)п"; е1ве сои» « "Экран занят.тп'; ге»игп О; Поскольку функция 161е() является членом класса с1, она имеет прямой доступ к переменной веа»ив, приналлежаьцей обьекту класса С1. Таким образом, любой объекг класса са необходимо передавать в функцию 1((1е () . Дружественные функции имеют лва важных ограничения. Во-первых, произволный класс не наследует дружественные функции. Во-вторых. лружественные функции не могут содержать спецификатор хранения, т.е. в ее объявлении нельзя использовать ключевые слова в»а»1с или еи»екп. ~й' Дружественные классы Один класс может быть дружественным по опюшению к другому. В атом случае дружественный класс и все его функции-члены имеют доступ к закрытым членам, определенным в другом классе.
Рассмотрим пример. // Применение дружественных классов. $1пс1ибе <Тов»геап> ив1по павеврасе в»б; с1авв Тмоуа1иев ( 1п» а: гп» Ь; риъъхс: Тмоуа1иев(ъп» 1, 1п» 3) ( а = 1; Ь = З; »гъепб с1авв нъп с1авв И1п ( риЬ11с: гп» ттп(Тмоуа1иев х) )з Глава 12. Классы и объекты 1пс Н1п::п1п(Т>гоуа1оев х) ( гееотп х.а < х.Ь Э х.а : х.Ь," ) 1ос па1о() ( Тес)га1оев оЬ(10, 20) г Мкп и; соос « п.п1п(оЬ) гесого 0; ) В данном примере класс м1о имеет доступ к закрытым переменным а и Ь, объявленным в классе Ттюзта1оев. Следует запомнитгп если олин класс является дружественным по отношению к другому, он просто получает доступ к сущностям, опрелеленным в этом классе, но не наследует их, т.е.
члены класса не становятся членами дружественного класса. Дружественные классы редко используются в практических приложениях. Они необходимы лишь в особых случаях. ~1~~ Подставляемые функции Язык С++ обладает нажным свойством. в нем сушествуют подставляемые функции ()пйпе бшсйопз), которые широко используются в классах.
В оставшейся части главы (и на протяжении всех книги) мы будем часто применять подставляемые функпии, поэтому рассмотрим их подробнее. В языке С++ можно написать короткую функнию, которая не вызывается, а подставляется в соответствуюшее место про~раины. Этот пронесс напоминает функниональную макроподстановку. Чтобы заменить вызов функнии подстановкой, перед ее опрелелением следует указать слово 1о11ое. Например, в слелуюшей программе функция пах(] не вызывается, а подставляется.
В1ос1о<)е <1овт сеап> ивьпд папеврасе вес; 1п1зпе ьпс пах(1пс а, 1пс ь) тееосо а>Ь з а : Ь; ) ьпе паьо() соие « пах(10, 20); соне « " " « пах(99, 86); гееогп 0; С точки зрения компилятора эта программа выглядит так. 41пс1иг)е <1ове севзп> ив1пд оапеврасе вМ; Часть й. Язык С++ 1пс юа1пП ( соце « (10>20 ? 10 „ 20); соцс « " " « (99>88 ? 99 : 88)г геецгп 0; Подставляемые функции позволяют создавать очень эффективные программы.
Поскольку классы обычно содержат несколько интерфейсных функций, которые зачастую вызываются лля доступа к его закрытым членам, необходимо, чтобы эти функции выполнялись как можно быстрее. Как известно, каждый вызов функции сопряжен с дополнительными затратами на передачу и возврат управления. Обычно при вызове функции ее аргументы заталкиваются в стек, а содержимое регистров копируется в оперативную память, чтобы после возврата управления можно было восстановить первоначальное состояние программы. На эти операции зат(ючивается дополнительное время.
Однако, если вместо вызова тело функции просто подставляется в программу, ничего этого не требуется. К сожалению, ускорение работы программы лостигается за счет увеличения размера кода, поскольку тело подставляемой функции дублируется несколько раз. По этой причине подставляемые функции должны быть очень маленькими. Кроме того, подставляемыми слелует делать только те функции, бысгролействие которых действительно сутцественно влияет на эффективность программы. Как и спецификатор тедввеет, ключевое слово 1пздпе является лишь рекомеядгл(ией, а не приказом компилятору.
В некоторых случаях компилятор может его проигнорировать. Кроме того, некоторые компиляторы ограничивают категории функций, которые могут быть подставляемыми. В частности, как правило, компиляторы не разрешают полставчять рекурсивные функции. В кажлом конкретном случае информацию об ограничениях на применение подставляемых функций следует искать в документации, сопровожлаюшей компилятор. Учтите, если функцию нельзя подставить, она будет вызываться.
Полставляемые функции могут быть членами класса. Например, следуюшая программа считается вполне корректной. №1пс1цс)е <ховсгеагп> цвьпд пвзаеврасе все)> с1авв ггус1авв ( №пс а, Ь; рцбььс: цо1а №пьг(№пе 1, №пт. З); тоьс) знои(); ) // Создать подставляемую функцию. хп1тпе уоЫ тус1авв::1п1с(№пс 1, 1пс б) ( а = 1„. Ь=б; ) Г! Создать другую подставляемую функцию. 1п1ьпе уогг) тус1авв::знои П соцс « в « " " « Ь « "1п"у Глава ) 2. Классы и объекты а = 1г Ь = зз ) уоьа внонО ( соне « а « " " « Ь « "~г1"; )з С технической точки зрения подсзвновка функции виси() не имеет смысла, поскольку время, затрачиваемое на ввод-вывод, намного превышает время, необходимое для вызова функции.
Однако полавляюшее большинство программистов предпочитает помешать все короткие функции-члены внутри объявления класса. (Крайне редко в профессиональных программах можно встретить короткие функции-члены, определенные вне объявления класса.) Конструктор и деструктор могут быть подставляемыми либо по умолчанию, если они определены внутри объявления класса, либо явно. ~4 Конструкторы с параметрами Конструкторам можно передавать аргументы, предназначенные для инициализации объекта.
Параметры конструктора задаются так же, как и для любой другой функции. Рассмотрим класс, конструктор которого имеет параметры. Вапс1и<)е <1оветеап> ия1пд папеярасе яЫз с1авя пус1аяя тпс а, Ь; рцЬ11с: пус1яяя (1пе 1, ъпе б ) (а=1; Ь=З; ) уотс( яном() (сацс «а « " " «Ь;) ); тпс паъп() ( пус1аяя оЬ(З, 51 оЬ.яном(); геецтп Ог ) Обратите внимание на то, что в определении конструктора а(уо1аввО параметры 1 н 5 используются лля инициализации членов я и Ь. Эта программа иллюстрирует наиболее распространенный способ задания аргументов при объявлении объекта, использующего конструктор с параметрами.
Например, оператор $ пус1аяя оЬ[3, 4); созлает объект оь и передает аргументам 1 и 5 конструктора пус1авв [) значения 3 и 4 Сушествует еше один способ передачи аргументов: $ пус1аяя оЬ = пус1яяя(3, 4); Глава 12. Классы и объекты Однако первый способ используется гораздо чаще. На салюм деле разница между этими двумя объявлениями невелика. Она связана с конструкторол? копирования, который мы обсудим в главе 14. Рассмотрим пример, иллюстрируюший применение конструктора с параметрами.
Б нем объявлен класс, объекты которого хранят информацию о библиотечных книгах. $1пс1ие)е <1овг оеар> В?пс1цде <свет?од> цв1пд папеврасе вес?? сосне 1пе ТН = 1: сопят 1пс СНЕСКЕВ ОПТ = О? с1авв Ьоо)г ( сиат атеист(40)? сиат сдс1е(40] ? Епс всаспв? риЬ1?сс Ьоои(сиат п, сиат *С, 1пе в); 1пс пес всаспя О (хеспхп всасив;) чоЫ вег.
всагцв(тпг. в) (всадя = в;) Ес? виси(1; )г Ьоо)с::Ьоок(спас *п, спас *с, 1пс в) астору(анспах, п); в?тору(съг1е, с); власия = вг чоЫ Ьоок.":виси() соне « С1С1е « '." « аиепот; соие « " находится 1?(веа?пв==1И) соил « "в библиотеке.лп"? е1ве соус « "у читателя.?п"? Тпс па1п() Ьоок Ь1("Твен", "Том Сойер', ти)? Ьоок Ь2('Мелвилл", "Моби Лик', С??ЕСКЕП ОПТ)? Ь1.виси(1; Ь2.виси(); тесптп О; ) Конструкторы с параметрами позволяют избежать применения отдельных функций для инициализации одной или нескольких переменных в объекте. Чем меньше функций вызывается в программе, тем выше ее эффективность.
Кроме того, обрпите внил?ание на то, что короткие функции яее веаепв() и вес всаепв() определены внутри объявления класса Ьоой, т.е. сделаны полставЛяемымн. Зтот прием часто применяется при создании программ на языке С++. Часть П. Язык С++ Конструкторы с одним параметром: особый случай Если конструктор имеет один параметр, возникает третий способ передачи начального значения. Рассмотрим следуюший пример Въпс1иг)е <гав»геап> ивзпп пвпеврасе в»г)г с1авв Х з.п» а) реЫЬс: х(ъп» д! ( а = з; Ъа» де»а() ( ге»сгп в; ) ): мз» тпаъп() ( Х аЬ = 99; // Передает параметру 5 значение 99. сас» « аЬ.де»а(); // Вывалит на экран число 99.
ге»огп 0; Здесь конструктор класса х имеет один параметр. Обратите особое внимание на способ объявления объекта аЬ а функции звали(). В этом случае число 99 автоматически передается параметру З конструктора хЕЬ Иначе говоря, компилятор считает этот оператор эквивалентным следуюшему: $ Х оЬ = Х(99]; Как правило, если конструктор имеет один аргумент, обьект можно инициализировать либо с помошью выражения ол(//, либо с помошью оператора од=/'.