246071-Либерти-Освой-самостоятельно-С-за-21-день (852741), страница 51
Текст из файла (страница 51)
Пример наследованияклассаDogотклассаMammalпоказанвлистинге11.1.Листинг11.1.Простоенаследование1://Листинг11.1.Простоенаследование2:3:#include<iostream.h>4:enumBREED{GOLDEN,CAIRN,DANDIE,SHETLAND,00BERMAN,LAB}5:6:classMammal7:{8:public:9://Конструкторы10:Mammal();11:~Mammal();12:13://Методыдоступакданным14:intGetAge()const;15:voidSetAge(int);16:intGetWeight()const;17:voidSetWeight();18:19://Другиеметоды20:voidSpeak()const;21:voidSleep()const;22:23:24:protected:25:intitsAge;26:intitsWeight;27:};28:29:classDog:publicMammal30:{31:public:32:33://Конструкторы34:Dog();35:~Dog();36:37://Методыдоступакданным38:BREEDGetBreed()const;39:voidSetBreed(BREED);40:41://Другиеметоды42:WagTail();43:BegForFood();44:45:protected:46:BREEDitsBreed;47:};Результат:Даннаяпрограмманичегоневыводитнаэкран,таккакпокасодержиттолькообъявленияиустановкиклассов.Никакихфункцийэтапрограммапоканевыполняет.Анализ:КлассMammalобъявляетсявстроках6—27.Обратитевнимание,чтоклассMammalнепроизводитсяниоткакогодругогокласса,хотявреальнойжизниможносказать,чтоклассмлекопитающих производится от класса животных.
Но в C++ всегда отображается не весьокружающий мир, а лишь модель некоторой его части. Действительность слишком сложна иразнообразна,чтобыотобразитьееводной,дажеоченьбольшойпрограмме.Профессионализмсостоит в том, чтобы с помощью относительно простой модели воспроизвести объекты,которыебудутмаксимальносоответствоватьсвоимреальнымэквивалентам.Иерархическая структура нашего мира берет свое начало неизвестно откуда, но нашаконкретная программа начинается с класса Mammal. В связи с этим некоторые переменныечлены, которые необходимы для работы базового класса, должны быть представлены вобъявленииэтогокласса.Например,всеживотныенезависимоотвидаипородыимеютвозрастивес.ЕслибыклассMammalпроизводилсяотклассаAnimals,томожнобылобыожидать,чтоон унаследует эти атрибуты. При этом атрибуты базового класса становятся атрибутамипроизведенногокласса.Чтобы облегчить работу с программой и ограничить ее сложность разумными рамками, вклассе Mammal представлены только шесть методов: четыре метода доступа, а также функцииSpeak()иSleep().Встроке29классDogнаследуетсяизклассаMammal.ВсеобъектыклассаDogбудутиметьтрипеременные-члена:itsAge,itsWeightиitsBreed.Обратитевнимание,чтовобъявленииклассаDog не указаны переменные itsAge и itsWeight.
Объекты класса Dog унаследовали этипеременные из класса Mammal вместе с методами, объявленными в классе Mammal, заисключениемкопировщика,конструктораидеструктора.ЗакрытыйилизащищенныйВозможно,вызаметили,чтовстроках24и45листинга11.1используетсяновоеключевоеслово protected. До сих пор данные класса определялись с ключевым словом private. Но членыкласса, объявленные как private, недоступны для наследования. Конечно, можно было впредыдущем листинге определить переменные-члены itsAge и itsWeight как public, но этонежелательно, поскольку прямой доступ к этим переменным получили бы все другие классыпрограммы.Нашуцельможносформулироватьследующимобразом:сделатьпеременную-членвидимойдля этого класса и для всех классов, произведенных от него.
Именно таковыми являютсязащищенныеданные,определяемыеключевымсловомprotected.Защищенныеданныедоступныдлявсехпроизведенныхклассов,нонедоступныдлявсехвнешнихклассов.Обобщим: существует три спецификатора доступа — public, protected и private. Если вфункцию передаются объекты класса, то она может использовать данные всех переменныхчленовифункций-членов,объявленныхсоспецификаторомpublic.Функция-членкласса,крометого, может использовать все закрытые данные этого класса (объявленные как private) изащищенные данные любого другого класса, произведенного от этого класса (объявленные какprotected).Так, в нашем примере функция Dog::WagTail() может использовать значение закрытойпеременнойitsBreedивсепеременныеклассаMammal,объявленныекакpublicиprotected.Даже если бы класс Dog был произведен не от класса Mammal непосредственно, а откакого-нибудь промежуточного класса (например, DomesticAnimals), все равно из класса DogсохранилсябыдоступкзащищеннымданнымклассаMammal,правдатольковтомслучае,есликласс Dog и все промежуточные классы объявлялись как public.
Наследование класса сключевымсловомprivateбудетрассматриватьсяназанятии15.В листинге 11.2 показано создание объекта в классе Dog с доступом ко всем данным ифункциямэтоготипа.Листинг11.2.Использованиеунаследованныхобъектов1://Листинг11.2.Использованиеунаследованныхобъектов2:3:#include<iostream.h>4:enumBREED<GOLDEN,CAIRN,DANDIE,SHETLAMD,DOBERMAN,LAB};5:6:classMammal7:{8:public:9://Конструкторы10:Mammal():itsAge(2),itsWeight(5){}11:~Mammal(){}12:13://Методыдоступа14:intGetAge()const{returnitsAge;}15:voidSetAge(intage){itsAge=age;}16:intGetWeight()const{returnitsWeight;}17:voidSetWeight(intweight){itsWeight=weight;}18:19://Другиеметоды20:voidSpeak()const{cout<<"Mammalsound!\n";}21:voidSleep()const{cout<<"shhh.I'msleeping.\n";}22:23:24:protected:25:intitsAge;26:intitsWeight;27:};28:29:classDog:publicMammal30:{31:public:32:33://Конструкторы34:Dog():itsBreed(GOLDEN){}35:~Dog(){}36:37://Методыдоступа38:BREEDGetBreed()const{returnitsBreed;}39:voidSetBreed(BREEDbreed){itsBreed=breed;}40:41://Другиеметоды42:voidWagTail()const{cout<<"Tailwagging...\n";}43:voidBegForFood()const{cout<<"Beggingforfood...\n";}44:45:private:46:BREEDitsBreed;47:};48:49:intmain()50:{51:Dogfido;52:fido.Speak();53:fido.WagTail();54:cout<<"Fidois"<<fido.GetAge()<<"yearsold\n";55:return0;56:}Результат:Mammalsound!Tailwagging...Fidois2yearsoldАнализ:Встроках6-27объявляетсяклассMammal(длякраткостителафункцийвставленыпоместуихвызовов).Встроках29—47изклассаMammalпроизводитсяклассDog.ВрезультатеобъектуFidoэтогоклассадоступныкакфункцияпроизводногоклассаWagTail(),такифункциибазовогоклассаSpeak()иSleep().КонструкторыидеструкторыОбъекты класса Dog одновременно являются объектами класса Mammal.
В этом сутьиерархических отношений между классами. Когда в классе Dog создается объект Fido, то дляэтого из класса Mammal вызывается базовый конструктор, называемый первым. Затемвызывается конструктор класса Dog, который завершает создание объекта. Поскольку объектFidoнеснабженникакимипараметрами,вобоихслучаяхвызываетсяконструктор,заданныйпоумолчанию. Объект Fido не существует до тех пор, пока полностью не будет завершено егосозданиесиспользованиемобоихконструкторовклассаMammalиклассаDog.При удалении объекта Fido из памяти компьютера сначала вызывается деструктор классаDog, а затем деструктор класса Mammal. Каждый деструктор удаляет ту часть объекта, котораябыласозданасоответствующимконструкторомпроизводногоилибазовогоклассов.Незабудьтеудалитьизпамятиобъект,еслионбольшенеиспользуется,какпоказановлистинге11.3.Листинг11.3.Вызовконструктораидеструктора1://Листинг11.3.Вызовконструктораидеструктора.2:3:#include<iostream.h>4:enumBREED{GOLDEN,CAIRN,DANDIE,SHETLAND,DOBERMAN,LAB};5:6:classMammal7:{8:public:9://конструкторы10:Mammal();11:~Mammal();12:13://Методыдоступа14:intGetAge()const{returnitsAge;}15:voidSetAge(intage){itsAge=age;}16:intGetWeight()const{returnitsWeight;}17:voidSetWeight(intweight){itsWeight=weight;}18:19://Другиеметоды20:voidSpeak()const{cout<<"Mammalsound!\n";}21:voidSleep()const{cout<<"shhh.I'msleeping.\n";}22:23:24:protected:25:intitsAge;26:intitsWeight;27:};28:29:classDog:publicMammal30:{31:public:32:33://Конструкторы34:Dog():35:~Dog();36:37://Методыдоступа38:BREEDGetBreed()const{returnitsBreed;}39:voidSetBreed(BREEDbreed){itsBreed=breed;}40:41://Другиеметоды42:voidWagTail()const{cout<<"Tailwagging...\n";}43:voidBegForFood()const{cout<<"Beggingforfood...\n";}44:45:private:46:BREEDitsBreed;47:};48:49:Mammal::Mammal():50:itsAge(1),51:itsWeight(5)52:{53:cout<<"Mammalconstructor...\n";54:}55:56:Mammal::~Mammal()57:{58:cout<<"Mammaldestructor...\n";59:}60:61:Dog::Dog():62:itsBreed(GOLDEN)63:{64:cout<<"Dogconstructor...\n";65:}66:67:Dog::~Dog()68:{69:cout<<"Dogdestructor...\n";70:}71:intmain()72:{73:Dogfido;74:fido.Speak();75:fido.WagTail();76:cout<<"Fidois"<<fido.GetAge()<<"yearsold\n":77:return0;78:}Результат:Mammalconstructor...Dogconstructor...Mammalsound!Tailwagging...Fidois1yearsoldDogdestructor...Mammaldestructor...Анализ: Листинг 11.3 напоминает листинг 11.2 за тем исключением, что вызовконструктораидеструкторасопровождаетсясообщениемобэтомнаэкране.Сначалавызываетсяконструктор класса Mammal, затем класса Dog.
После этого объект класса Dog полноценносуществует и можно использовать все его методы. Когда выполнение программы выходит заобластьвидимостиобъектаFido,вызываетсяпарадеструкторов,сначалаизклассаDog,азатемизклассаMammal.Передачааргументоввбазовыеконструкторы Предположим, нужно перегрузить конструкторы, заданные по умолчанию в классахMammal и Dog, таким образом, чтобы первый из них сразу присваивал новому объектуопределенныйвозраст,авторой—породу.КакпередатьвконструкторклассаMammalзначениявозрастаивесаживотного?Чтопроизойдет,есливеснебудетустановленконструкторомклассаMammal,затоегоустановитконструкторклассаDog?Чтобывыполнитьинициализациюбазовогокласса,необходимозаписатьимякласса,послечегоуказатьпараметры,ожидаемыебазовымклассом,какпоказановлистинге11.4.Листинг11.4.Перегрузкаконструктороввпроизводныхклассах1://Листинг11.4.Перегрузкаконструктороввпроизводныхклассах2:3:#include<iostream.h>4:enumBREED{GOLDEN,CAIRN,DANDIE,SHETLAND,D0BERMAN,LAB};5:6:classMammal7:{8:public:9://Конструкторы10:Mammal();11:Mammal(intage);12:~Mammal();13:14://Методыдоступа15:intGetAge()const{returnitsAge;}16:voidSetAge(intage){itsAge=age;}17:intGetWeight()const{returnitsWeight;}18:voidSetWeight(intweight){itsWeight=weight;}19:20://Другиеметоды21:voidSpeak()const{cout<<"Mammalsound!\n";}22:voidSleep()const{cout<<"shhh.I'msleeping.\n";}23:24:25:protected:26:intitsAge;27:intitsWeight;28:};29:30:classDog:publicMammal31:{32:public:33:34://Конструкторы35:Dog();36:Dog(intage);37:Dog(intage,intweight);38:Dog(intage,BREEDbreed);39:Dog(intage,intweight,BREEDbreed);40:~Dog();41:42://Методыдоступа43:BREEDGetBreed()const{returnitsBreed;}44:voidSetBreed(BREEDbreed){itsBreed=breed;}45:46://Другиеметоды47:voidWagTail()const{cout<<"Tailwagging,..\n";}48:voidBegForFood()const{cout<<"Beggingforfood...\n";}49:50:private:51:BREEDitsBreed;52:};53:54:Mammal::Mammal():55:itsAge(1),56:itsWeight(5)57:{58:cout<<"Mammalconstructor...\n";59:}60:61:Mammal::Mammal(intage):62:itsAge(age),63:itsWeight(5)64:{65:cout<<"Mammal(int)constructor...\n";66:}67:68:Mammal::~Mammal()69:{70:cout<<"Mammaldestructor...\n";71:}72:73:Dog::Dog();74:Mammal(),75:itsBreed(GOLDEN)76:{77:cout<<"0ogconstructor...\n";78:}79:80:Dog::Dog(intage):81:Mammal(age),82:itsBreed(GOLDEN)83:{84:cout<<"Dog(int)constructor...\n";85:}86:87:Dog::Dog(intage,intweight):88:Mammal(age),89:itsBreed(GOLDEN)90:{91:itsWeight=weight;92:cout<<"Dog(int,int)constructor...\n";93:}94:95:Dog::Dog(intage,intweight,BREEDbreed):96:Mammal(age),97:itsBreed(breed)98:{99:itsWeight=weight;100:cout<<"Dog(int,int,BREED)constructor...\n";101:}102:103:Dog::Dog(intage,BREEDbreed):104:Mammal(age),105:itsBreed(breed)106:{107:cout<<"Dog(int,BREED)constructor...\n";108:}109:110:Dog::~Dog()111:{112:cout<<"Dogdestructor...\n";113:}114:intmain()115:{116:Dogfido;117:Dogrover(5);118:Dogbuster(6,8);119:Dogyorkie(3,GOLDEN);120:Dogdobbie(4,20,DOBERMAN);121:fido.Speak();122:rover.WagTail();123:cout<<"Yorkieis"<<yorkie.GetAge()<<"yearsold\n";124:cout<<"Dobbieweighs";125:cout<<dobbie.GetWeight()<<"pounds\n";126:return0;127:}Примечание:Для удобства дальнейшего анализа строки вывода программы на экранпронумерованы.Результат:1:Mammalconstructor...2:Dogconstructor...3:Mammal(int)constructor...4:Dog(int)constructor...5:Mammal(int)constructor...6:Dog(int,int)constructor...7:Mammal(int)constructor...8:Dog(int,BREED)constructor....9:Mammal(int)constructor...10:Dog(int,int,BREED)constructor...11:Mammalsound!12:Tailwagging...13:Yorkieis3yearsold.14:Dobbieweighs20pounds.15:Dogdestructor..,16:Mammaldestructor...17:Dogdestructor...18:Mammaldestructor...19:Dogdestructor...20:Mammaldestructor...21:Dogdestructor...22:Mammaldestructor...23:Dogdestructor,..24:Mammaldestructor...Анализ: В листинге 11.4 конструктор класса Mammal перегружен в строке 11 такимобразом, чтобы принимать целочисленные значения возраста животного.