Г. Шилтд - Самоучитель C++ (DJVU) (1114955), страница 32
Текст из файла (страница 32)
2. В следующей программе показано, что происходит, если защищенные члены класса наследуются как открытые: Нпс1пс)е <товстеаш> пз)пя патпсзрасе ась с)азз Ьазе ( рто~есбес(: тпс а,Ь; рвЬ11с: уоЫ зеТаЬ(тс и, тпТ т) ( а=п; Ь=-ш; ) с1авв беттчес): риЬ1тс Ьаве ( тпь с; рпЬ1ас: чей васс().пе и) ( с = и,.
эта Функция имеет доступ к переменным а и Ь класса Ьазе чоЫ зЬоыаЬс 0 ( сонь « а « ' ' « Ь « ' " « с « '~п'; /* Переменные а и Ь здесь недостутлты, поскольку являются закрытыми членами классов Ьазе и йеттуес( оЬ.весаЬ(1, 2) оЬ.весе(3); оЬ.вЬоыаЬс(); теентп 0; тпсшатп ( ) с)еттчео оЬ; закрытые члены класса Ьазе, но для производного класса они доступны Глава Наследование Поскольку переменные а и Ь в классе Ьаве защищены и наследуются произ- водным классом Нег(те(( как открытые члены, они доступны для использова- ния функциями — членами класса йептей.
Однако вне двух этих классов они в полной мере закрыты и недоступны. 3. Как упоминалось ранее, если базовый класс наследуется как защищенный, открытые и защищенные члены базового класса становятся защищенными членами производного класса. Например, в слегка измененной версии программы из предыдущего примера класс Ьаве наследуется не как открытый, а как защищенный: // Эта программа компилироваться не будет ()1пс1пйе <1овТгеат> ив1пд пагпеврасе вТй„" с(авв Ьаве ргосессей: 1пт а|Ь) рпЬ1 1с: чотй веТаЬ(1пТ г., 1пс ж) а=п; Ь=тв( ) // класс Ьаве наследуется как зандлценный с1аяв йегтуей: ргосессей Ьаве 1пс с) рсЬ11с: чотй веТс(хпТ и) ( с = и; к переменным а и Ь класса Ьаве эта Функция имеет доступ чотй в)тоыаЬс () ( соцТ « а « ' ' « Ь « « ~п г ОШИЬКА: теперь функция весаЬ() является зацищенньлч членом класса Ьаве оЬ,веТаЬ(1, 2); /! функция веТаЬ() здесь недоступна Как указано в комментариях, поскольку класс Ьахе наследуется как защи- щенный, его открытые и защищенные элементы становятся защищенными членами производного класса Нег(тей и следовательно внутри функции вша)вО они недоступны.
1пк ваха О йеггуей оЬ; оЬ.веТс(3)) оЬ вноыаЬс ( ) г гегпгп О; закрытые члены класса Ьаве, но для производного класса они доступны 21б Самоучитель С++ 1. Что происходит с защищенным членом класса, когда класс наследуется как открытый? Что происходит, когда он наследуется как закрытый? 2. Объясните, зачем нужна категория защищенности ргогес1ед? 3. В вопросе 1 из раздела 7.1, если бы переменные а и Ь внутри класса тус1авз стали не закрытыми (по умолчанию), а защищенными членами, изменился бы какой-нибудь из ваших ответов на вопросы этого упражнения? Если да, то почему? 7.3.
Конструкторы, деструкторы и наследование Базовый класс, производный класс или оба класса вместе могут иметь конструкторы и/или деструкторы. В этой главе исследуется несколько следствий такого положения. Если у базового и у производного классов имеются конструкторы и деструкторы, то конструкторы выполняются в порядке наследования, а деструкторы — в обратном порядке. Таким образом, конструктор базового класса выполняется раньше конструктора производного класса. Для деструкторов правилен обратный порядок: деструктор производного класса выполняется раньше деструктора базового класса.
Последовательность выполнения конструкторов и деструкторов достаточно очевидна. Поскольку базовый класс "не знает" о существовании производного, любая инициализация выполняется в нем независимо от производного класса и возможно становится основой для любой инициализации, выполняемой в производном классе. Поэтому инициализация в базовом классе должна выполняться первой.
С другой стороны, деструктор производного класса должен выполняться раньше деструктора базового класса потому, что базовый класс лежит в основе производного. Если бы деструктор базового класса выполнялся первым, это бы разрушило производный класс. Таким образом, деструктор производного класса должен вызываться до того, как объект прекратит свое существование.
Пока что ни в одном из предыдущих примеров мы не передавали аргументы для конструктора производного или базового класса. Однако это вполне возможно. Когда инициализация проводится только в производном классе, аргументы передаются обычным образом. Однако при необходимости передать аргумент конструктору базового класса ситуация несколько усложняется. Во-первых, все необходимые аргументы базового и производного классов передаются конструктору производного класса.
Затем, используя Наследование 217 Глина расширенную форму объявления конструктора производного класса, соответствующие аргументы передаются дальше в базовый класс. Синтаксис передачи аргументов из производного в базовый класс показан ниже: конструктор пронзи класса(список-арг,' базой класс(список арт) , г' зало конструктора производного класса Для базового и производного классов допустимо использовать одни и те же аргументы. Кроме этого, для производного класса допустимо игнорирование всех аргументов и передача их напрямую в базовый класс. 1.
В этой очень короткой программе показано, в каком порядке выполняются конструкторы и деструкторы базового и производного классов: ((тпс1пбе <(.овегеап> пз(пд папзезрасе з1с(; с1авв Ьаае ( рпЫ(с: Ьазе () ( сон1 « "Работа конструктора базового кпассатп"; ) -Ьазе() ( сопс « "Работа деструктора базового класса~п" ( с1азз с(ет)ь ес1: роЬ1(с Ьазе ( рпЬ1(с: с(ег)уес(о 1 сов1 « "Работа конструктора производного класса'(и"; -с(еттзес(() 1 сов1 « "Работа деструктора производного кпассасп": ) 1пс паз.п ( ) дега сед о; тесатп О; После выполнения программы на экран выводится следуюшее: Работа конструктора базового класса Работа конструктора производного класса Работа деструктора производного класса Работа деструктора базового класса Как видите, конструкторы выполняются в порядке наследования, а деструк- торы — в обратном порядке.
Самоучитель С++ 218 2. В этой программе показана передача аргумента конструктору производного класса: ()1пс1ис(е <1оаТгеаж> нятпд патеярасе втб) с1аяя Ьаяе ( риЫ1с: Ьаае() ( соне « "Работа конструктора базового класса1п"; ) -Ьаае () ( сонг « "Работа деструктора базового хласса~п"г ) с1аьв бег)уесй риЬИс Ьаяе (ттт з') рнЬ11с: бегттес((1пс и) ( соне « "Работа конструктора производного класса М"; -бегтъябО ( сонг « "Работа деструктора производного класса1п"; уотс) япоиз() ( сонг « « '1п'г 1по ва1п() беквчеб о (1()); 0,5Ьоиз () ) гебдгн О; Обратите внимание, что аргумент передается конструктору производного класса обычным образом.
3. В следующем примере у конструкторов производного и базового классов имеются аргументы. В этом особом случае оба конструктора используют один и тот же аргумент, и производный класс просто передает этот аргумент в базовый класс. ()1пс1ибе <1оастеав> из(па патпеярасе згд; с1аяя Ьаяе 1пт 1; рсЫ1с: Ьаве (з.пТ и) сон1 « "Работа конструктора базового класса1п"г 1 — и; Глава 7. Наследование -ЬааеО ( сон( « "Работа деструктора базового класса~в"; уоЫ виои1() ( соШ « ) « '~п'; ) с1авв бегучей: раЬ11с Ьаве ( (ис З; риЫ1с: бег1чей(1пС п): Ьаве (п) ( // передача аргумента // в базовый класс соис « "Работа конструктора производного класса~и"; ) с(ег1уеб О ( сонг « "Работа деструктора производного класса~и"; чо1б вЬоиЗ () ( сонг « З « '',п'; ) 1и" па1и () с(ег1уес( о (10) ' о.впои1(); о.впоиЗ()~ геонги 0; Обратите особое внимание на объявление конструктора производного класса.
Отметьте, как параметр и (который получает аргумент при инициализации) используется в конструкторе дегЬед() и передается конструктору ЬавеО. 4. Обычно конструкторы базового и производного классов не используют один и тот же аргумент. В этом случае, при необходимости передать каждому конструктору класса один или несколько аргументов, вы должны передать конструктору производного класса все аргументы, необходимые конструкторам обоих классов.
Затем конструктор производного класса просто передает конструктору базового класса те аргументы, которые ему требуются. Например, в представленной ниже программе показано, как передать один аргумент конструктору производного класса, а другой — - конструктору базового класса: ((1пс1ис$е <1оввгеав> нк)па паптеврасе в(д; с)акк Ьаке 1пб (; рпЫ1с: Ьазе(1пс и) соШ « "Работа конструктора базового класса~и"г = п; Самоучитель С~--" -Ьаяе() ( сопб « "Работа деструктора базового класса1п"; чогй яЬои1() ( сонг « 1 « ''~п'г ) с1аяв аегучей: рпЬ11с Ьаяе 1пг ]; риЬ11с: йег1чей(1пг и, 1пс т) : Ьаве (т) ( // передача аргумента /! в базовый класс сопя « "Работа конструктора производного класса~а"; = п; -йег1чей() ( сопя « "Работа деструктора ггроизводного класса1п"; ъогй я)тсмэ() ( соне « 0 « '1П'Г зпс гпа1п() йег1чео о (10, 20); о.впои1(); о.вйоиз(); гегпгп 0; 5.