Г. Шилтд - Самоучитель C++ (DJVU) (1114955), страница 34
Текст из файла (страница 34)
в)тон (); тетшп 0) В этой версии программы класс (:) передает аргументы по отдельности классам В) и В2. Теперь иерархия классов выглядит таким образом: В1 В2 3. В следующей программе показан порядок, в котором вызываются конструкторы и деструкторы, когда производный класс прямо наследует несколько базовых классов: () з.пс1пс)е <1оветеаттт> ик)пя патпеарасе аЫт с)ааа В! ( рнЬ11с: В1() ( сои( « "Работа конструктора класса В1~п"; -В1() ( сонт « "Работа деструктора класса В11п"т ) ) Самоучитель с1аяя В2 гпв Ь; рпЪ11с: В2 ( ) ( сорб « "Работа конструктора класса В2М -В2 ( ) ( соиТ « "Работа деструктора класса В21п"г Наследование с1аяя Р: риЬ11с рпЬ11с: Р () ( сопв -Р() ( сопс двух базовьяс классов В1, рпЬ11с В2 « "Работа конструктора класса Р~п"; « "Работа деструктора класса Р~п"; тпе па1п () Р оЬ; теЬс сп О; Эта программа выводит на экран следующее: Работа Работа Как уже установлено, когда прямо наследуются несколько базовых классов, конструкторы вызываются слева направо в порядке, задаваемом списком.
Деструкторы вызываются в обратном тюрядке. 1. Что выводит на экран следующая программа? (Попытайтесь определить это, не запуская программу.) ()1пс1пе(е <тояетеата> дятла пашеярасе ясс(; с1аяя А ( рпЪ11с: А ( ) ( сопс « "Работа конструктора класса А1п"; -А ( ) ( сопя « "Работа деструктора класса Мп" г ) Работа Работа Работа Работа конструктора класса В1 конструктора класса В2 конструктора класса Р деструктора класса Р деструктора класса В2 деструктора класса В1 Глава Наследование рнЫ (с й, раЫ(с В ьпг пи1п ( ) С оЬ; геСигп 0; 2.
Используя следующую иерархию классов, создайте конструктор класса С так, чтобы он инициализировал переменную )( и передавал аргументы конструкторам АО и ВО. ()ьпс1пс)е <Ьовггеап~> па)пя паптеарасс зТс(; с1азв А ( )пг 1; риЫ)с: й(тпд а) ( 1 а; с1аяя В ьп'с рпЫ Ьс: В(1пса) ( ) = а; ) )' с1аяя С: риЫтс А, рагс В ( тпе )с; роЫьс; /* Создайте такой конструктор С(), чтобы он инициализировал переменную к и передавал аргументы конструкторам Л() и ВО */ )' 7.5.
Виртуальные базовые классы При многократном прямом наследовании производным классом одного и того же базового класса может возникнуть проблема. Чтобы понять, что это за проблема, рассмотрим следующую иерархию классов: с1аяя В раас: в() -В () ); с1аяя С: рыЫ1 с: с() -с () соыс « "Работа конструктора класса В~п"; ) ( сонг « "Работа деструктора класса В~п"; ) ( соыГ « "Работа конструктора класса С~П"; ) ( соне « "Работа деструктора класса С~п"; ) Самоучитель С++ 230 Базовый Базовый Про нзводный2 Пронзводный1 Производный 3 Здесь базовый класс Базовый наследуется производными классами Производный1 и Ироизводный2. Производный класс ПроизводныйЗпрямо наследует производные классы Производный1и Производный2.
Однако это подразумевает, что класс Базовый фактически наследуется классом ПроизводныйЗ дважды — первый раз через класс Производный1, а второй через класс Производный2. Однако, если член класса Базовый будет использоваться в классе ПроизводныйЗ, это вызовет неоднозначность.
Поскольку в классе ПроизводныйЗ имеется две копии класса Базовый, то будет ли ссылка на элемент класса Базовый относиться к классу Базовый, наследуемому через класс Производный1,или к классу Базовый, наследуемому через класс Производный2? Для преодоления этой неоднозначности в С++ включен механизм, благодаря которому в классе ПроизводныйЗ будет включена только одна копия класса Базовый.
Класс, поддерживающий этот механизм, называется виртуальным базовым классом (тана! Ьазе с!азз). В таких ситуациях, когда производный класс более одного раза косвенно наследует один и тот же базовый класс, появление двух копий базового класса в объекте производного класса можно предотвратить, если базовый класс наследуется как виртуальный для всех производных классов.
Такое наследование не дает появиться двум (или более) копиям базового класса в любом следующем производном классе, косвенно наследующем базовый класс. В этом случае перед спецификатором доступа базового класса необходимо поставить ключевое слово у!г1ва1. В этом примере для предотвращения появления в классе 4ег1те63 двух копий класса Ьаве используется виртуальный базовый класс. В этой ппогравлке используется виртуальяьлл базовый класс втпс1пс!е <товткеал> пвтпд папез1оасе з1.Й Глава Наследование с1аяя Ьаяе роЫ1с: 1пЬ 1; )) Наследование класса Ьаяе как виртуального с1авя с)егьуео1: уггсиа1 рагс Ьаяе ( рпЫ1с; 1пс 5; Г/ Здесь класс Ьаяе тоже наследуется как виртуальный с1аяя <)ег1уеб2: льгсиа1 рпЫ1с Ьаяе риЫ1с: 1пг )) /* Здесь класс бегьчес)З наследует как класс бегтуес)1, так и класс с)егьуес)2.
Однако в классе с)ег1уес)3 создается только одна копия класса Ьаяе * / с1аяв с)егтуейЗ: рпЫ1с оегглес)1, рпЫ1с аегттес)2 ( рпЫ 1с: гп ргос)исг 1) ( гегигп 1 * 5 * 1п1 паап () с)егьуес)З оЬ; // Здесь нет неоднозначности, поскольку // представлена только одна копия класса Ьазе оЬ. 1 — 10; оЬЗ=З) оЬ.)с = 5; ' ~п'; сопл « "Результат равен " « оЬ.ргос)ног() « гегнгп 0; Если бы классы бег)тей! и йег1уе62 наследовали класс Ьазе не как виртуальный,тогдаинструкция оЬл — 10; вызывала бы неоднозначность и при компиляции возникла бы ошибка. (См. представленное ниже упражнение 1.) 2. Важно понимать, что даже если базовый класс наследуется производным как виртуальный, то копия этого базового класса все равно существует внутри 232 Самоучитель С+~- производного.
Например, по отношению к предыдущей программе этот фрагмент совершенно правилен: деть'те61 оЬ; оЬ1 = 1ОО; Отличие между обычным и виртуальным базовыми классами проявляется только тогда, когда объект наследует базовый класс более одного раза. Если используются виртуальные базовые классы, то в каждом конкретном объекте присутствует копия только одного из них. В противном случае (при обычном наследовании) там было бы несколько копий. 1, В программе из примера 1 удалите ключевое слово чг1иа1 и попытайтесь отком- пилировать программу.
Обратите внимание на виды ошибок. 2. Объясните, зачем может понадобиться виртуальный базовый класс. Теперь вам необходимо выполнить следующие упражнения и ответить на вопросы: 1. Создайте исходный базовый класс ЬшЫшя для хранения числа этажей и комнат в здании, а также общую площадь комнат. Создайте производный класс Ьоиае, который наследует класс Ьиййпц и хранит число ванных комнат и число спален.
Кроме этого создайте производный класс оГйее, который наследует класс Ьв11йпя и хранит число огнетушителей и телефонов. (Замечание. Ваше решение может отличаться от приведенного в конце книги. Однако, если функционально оно такое же, считайте его правильным.) 2. Когда базовый класс наследуется производным классом как открытый, что происходит с его открытыми членами? Что происходит с его закрытыми членами? Когда базовый класс наследуется производным классом как закрытый, что происходит с его закрытыми и открытыми членами? 3. Объясните, что означает ключевое слово рго1ес1ед.
(Рассмотрите два случая: когда оно используется для задания элементов класса и когда оно используется в качестве спецификатора доступа.) 4. При наследовании одного класса другим, когда вызываются конструкто- ры классов? Когда вызываются их деструкторы? Наследование Глава 5. Дан следующий фрагмент программы, впишите детали, как указано в комментариях: ()тпс1цс)е <1ов~геаш> пвтпо патпеврасе вгФ с1авв р1апег ргосессей: с)опЬ1е бтв апсе; // расстояние в милях от Солнца 1пг гечо1че; // тюлный оборот Б днях рпЫгс: р1апеГ (г(опЫе й, тпг г) ( бтвгапсе =- г(; гечо1че = )' с1авв еаггЬ: рцЬ11с р1апег ( г)опЬ1е стгспшбегепсе; // окружность орбиты рпЫгс: /* Создайте конструктор еагГЬ (оопЫе с(, тп г) .
Он должен передавать классу р1апег расстояние и число оборотов, а также рассчитывать окружность орбиты (Подсказка: окружность = 2г * 3.141б.) /* Создайте функцию в)тон() для вывода информации на экран */ ); 1пс ша|п () еагГЬ оЬ(93000000, Збб); оЬ впоы() гегпгп О; б. Исправьте следующую программу: /* Вариация иерархии классов из примера с классом чеМс1е. В программе имеется ошибка.
найдите ее. Подсказка: попытайтесь провести компиляцюл и изучите сообщения об ошибках */ ()1пс1пс(е <1оз~геаш> пвгпд пашеврасе вгс(; Базовый класс для автомобилей разных типов С1авв чеМс1е ( гпб ппш м)тее1в; ггА галде; рпЫтс: чеЬгс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е(ьт, раявепуегя — р; ) тто1б вЬоиг() ( соив « "Пассазироеьткость" « раяяепуегя « 'т,п'т епттттт вгеег1пу (роиег, гасК у 1пзотт, птапиа1); с) аяя саг т риЫ1с тттосог1зеб, риЫ1с гоаб изе ( епиттт явеегппу вГгпд; риЫ.1с т саг(епиттт явееггпу в, епиттт тосог ттт, 1пг и, 1пс г, 1пс р) Глава 7, Наследование гоас( иве(р, уу, г), поеогГаес1(га, уу, г), чегигс1е(и, Г) атгпя = з; у01Й врон ( ) ( вйоупг(); *понг(); вноип()) СОШ « "управление:"; ви.' сс)1 (в-гпп) ( сазе роу(ег: сош « "Силовой привоНп"; 'огеа(с; саке гас)г ртпГоп.