246071-Либерти-Освой-самостоятельно-С-за-21-день (852741), страница 68
Текст из файла (страница 68)
Если впрограмме используется небольшой класс, от которого не производятся подклассы, то виспользованиивиртуальныхфункцийнетникакогосмысла.Вкакихслучаяхиспользуютсявиртуальныедеструкторы?Виртуальныедеструкторыследуетописыватьвтомслучае,есливпрограммепланируетсяиспользование указателя базового класса для получения доступа к объектам подклассов.Существует одно простое правило: если в программе описываются виртуальные функции, тообязательнодолжныиспользоватьсявиртуальныедеструкторы.Для чего возиться с созданием абстрактных типов данных? Не проще ли создать обычныйбазовыйкласс,длякоторогопростонесоздаватьобъектоввпрограмме?При написании программы всегда следует использовать такие подходы, которыегарантировали бы обнаружение ошибок в программе не во время ее выполнения, а во времякомпиляции.Есликлассявнобудетописанкакабстрактный,толюбаяпопыткасоздатьобъектэтогоклассаприведеткпоказукомпиляторомсообщенияобошибке.КоллоквиумВэтомразделепредлагаютсявопросыдлясамоконтроляиукрепленияполученныхзнанийи приводится несколько упражнений, которые помогут закрепить ваши практические навыки.Попытайтесьсамостоятельноответитьнавопросытестаивыполнитьзадания,апотомсверьтеполученные результаты с ответами в приложении Г.
Не приступайте к изучению материаласледующей главы, если для вас остались неясными хотя бы некоторые из предложенных нижевопросов.Контрольныевопросы1.Чтотакоеприведениетипаобъектавниз?2.Чтотакоеv-ptr?3.Предположим,длясозданияпрямоугольникасзакругленнымиугламииспользуетсяклассRoundRect, произведенный от двух базовых классов — Rectangle и Circle, которые, в своюочередь,производятсяотобщегоклассаShape.КакмногообъектовклассаShapeсоздаетсяприсозданииодногообъектаклассаRoundRect?4.ЕсликлассыHorseиBirdвиртуальнонаследуютсяотклассаAnimalкакоткрытые,будутликонструкторыэтихклассовинициализироватьконструкторклассаAnimal?ЕсликлассPegasusнаследуется сразу от двух классов, Horse и Bird, как в нем будет инициализироватьсяконструкторклассаAnimal?5.ОбъявитеклассVehicle(Машина)какабстрактныйтипданных.6. Если в программе объявлен класс ADT с тремя чистыми виртуальными функциями,сколькоизнихнужнозаместитьвпроизводныхклассах,чтобыполучитьвозможностьсозданияобъектовэтихклассов?Упражнения1.
Объявите класс JetPlane (Реактивный самолет), наследуя его отдвух базовых классов —Rocket(Ракета)иAirplane(Самолет).2.ПроизведитеотклассаJetPlane,объявленноговпервомупражнении,новыйкласс747.3.Напишитепрограмму,производящуюклассыCar(Легковойавтомобиль)иBus(Автобус)от класса Vehicle (Машина). Объявите класс Vehicle как абстрактный тип данных с двумячистымивиртуальнымифункциями.КлассыCarиBusнедолжныбытьабстрактными.4.Изменитепрограммуизпредыдущегоупражнениятакимобразом,чтобыклассCarтожесталADT,ипроизведитеотнеготриновыхкласса:SportsCar(Спортивныйавтомобиль),Wagon(Фургон) и Coupe (Двухместный автомобиль-купе).
В классе Car должна замещаться одна извиртуальныхфункций,объявленныхвклассеVehicle,свызовомфункциибазовогокласса.День14-й.СпециальныеклассыифункцииЯзык программирования C++ предлагает несколько способов ограничения областивидимости и использования переменных и указателей. В предыдущих главах вы научилисьсоздаватьглобальныепеременные,используемыевовсейпрограмме,илокальныепеременные,используемые в отдельных функциях.
Вы узнали, что собой представляют указатели напеременныеипеременные-членыкласса.Сегоднявыузнаете:•Чтотакоестатическиепеременные-членыифункции-члены•Какиспользуютсястатическиепеременные-членыифункции-члены•Каксоздаватьиприменятьуказателинафункцииинафункции-члены•КакработатьсмассивамиуказателейнафункцииСтатическиепеременные-членыДо настоящего момента вы считали, что всякие данные объекта уникальны для тогообъекта, в котором используются, и не могут совместно применяться несколькими объектамикласса. Другими словами, если было создано пять объектов Cat, то каждый из ниххарактеризуется своим временем жизни, размерами и т.п.
При этом время жизни одного невлияетнавремяжизниостальных.Однако иногда возникает необходимость контроля за накоплением данных программой.Может потребоваться информация о том, сколько всего было создано объектов определенногокласса и сколько их существует в данный момент. Статические переменные-члены совместноиспользуются всеми объектами класса. Они являются чем вроде "золотой серединки" междуглобальными данными, доступными всем частям программы, и данными членов, доступными,какправило,толькоодномуобъекту.Можно полагать, что статические члены принадлежат классу, а не объекту.
Если данныеобычных членов доступны одному объекту, то статические члены могут использоваться всемклассом. В листинге 14.1 объявляется объект Cat со статическим членом HowManyCats. Этапеременная учитывает количество созданных объектов Cat, что реализуется приращениемстатической переменной HowManyCats при вызове конструктора или отрицательнымприращениемпривызоведеструктора.Листинг14.1.Статическиепеременные-члены1://Листинг14.1.Статическиепеременные-члены2:3:#include<iostream.h>4:5:classCat6:{7:public:8:Cat(intage):itsAge(age){HowManyCats++;}9:virtual~Cat(){HowManyCats--;}10:virtualint6etAge(){returnitsAge;}11:virtualvoidSetAge(intage){itsAge=age;}12:staticintHowManyCats;13:14:private:15:intitsAge;16:17:};18:19:intCat::HowManyCats=0;20:21:intmain()22:{23:constintMaxCats=5;24:inti;Cat*CatHouse[MaxCats];25:for(i=0;i<MaxCats;i++)26:CatHouse[i]=newCat(i);27:28:for(i=0;i<MaxCats;i++)29:{30:cout<<"Thereare";31:cout<<Cat::HowManyCats;32:cout<<"catsleft!\n";33:cout<<"Deletingtheonewhichis";34:cout<<CatHouse[i]->GetAge();35:cout<<"yea.rsold\n";36:deleteCatHouse[i];37:CatHouse[i]=0;38:}39:return0;40:}Результат:Thereare5catsleft!Deletingtheonewhichis0yearsoldThereare4catsleft!Deletingtheonewhichis1yearsoldThereare3catsleft!Deletingtheonewhichis2yearsoldThereare2catsleft!Deletingtheonewhichis3yearsoldThereare1catsleft!Deletingtheonewhichis4yearsoldАнализ: Обычный класс Cat объявляется в строках 5—17.
С помощью ключевого словаstaticвстроке12объявляетсястатическаяпеременная-членHowManyCatsтипаint.Объявление статической переменной HowManyCats само по себе не определяет никакогоцелочисленного значения, т.е. в памяти компьютера не резервируется область для даннойпеременной при ее объявлении, поскольку, по сути, она не является переменной-членомконкретногообъектаCat.ОпределениеиинициализацияпеременнойHowManyCatsпроисходитвстроке19.Не забывайте отдельно определять статическую переменную-член класса (весьмараспространенная ошибка среди начинающих программистов). В противном случае редакторсвязейвовремякомпиляциипрограммывыдастследующеесообщениеобошибке:undefinedsymbolCat::HowManyCatsОбратите внимание, что для обычной переменной-члена itsAge не требуется отдельноеопределение, поскольку обычные переменные-члены определяются автоматически каждый разприсозданииобъектаCat,как,например,встроке26.Конструктор объекта Cat, объявленный в строке 8, увеличивает значение статическойпеременной-членанаединицу.Деструктор,объявленныйвстроке9,уменьшаетэтозначениена1.
Таким образом, в любой момент времени переменная HowManyCats отражает текущееколичествосозданныхобъектовклассаCat.Встрокахпрограммы21—40создаетсяпятьобъектовCat,указателинакоторыезаносятсявмассив.ЭтосопровождаетсяпятьювызовамиконструктораклассаCat,врезультатечегопятьразпроисходитприращениенаединицупеременнойHowManyCats,начинаясисходногозначения0.Затем в программе цикл for последовательно удаляет все объекты Cat из массива,предварительновыводянаэкрантекущеезначениепеременнойHowManyCats.Выводначинаетсясозначения5(ведьбылосозданопятьобъектов)искаждымцикломуменьшается.Обратитевнимание:переменнаяHowManyCatsобъявленакакpublicиможетвызыватьсяизфункции main().
Однако нет веских причин объявлять эту переменную-член таким образом.Если предполагается обращаться к статической переменной только через объекты класса Cat,предпочтительней сделать ее закрытой вместе с другими переменными-членами и создатьоткрытыйметоддоступа.Сдругойстороны,еслинеобходимополучатьпрямойдоступкданнымбезиспользованияобъектаCat,томожнолибооставитьееоткрытой,какпоказановлистинге14.2, либо создать статическую функцию-член. Реализация последнего вариантарассматриваетсядалеевэтойглаве.Листинг14.2.Доступкстатическимчленамбезиспользованияобъектов1://Листинг14.2.Статическиепеременные-члены2:3:#include<iostream.h>4:5:classCat6:{7:public:8:Cat(intage):itsAge(age){HowManyCats++;}9:virtual~Cat(){HowManyCats--;}10:virtualintGetAge(){returnitsAge;}11:virtualvoidSetAge(intage){itsAge=age;}12:staticintHowManyCats;13:14:private:15:intitsAge;16:17:};18:19:intCat::HowManyCats=0;20:21:voidTelepathicFunction();22:23:intmain()24:{25:constintMaxCats=5;inti;26:Cat*CatHouse[MaxCats];27:for(i=0;i<MaxCats;i++)28:{29:CatHouse[i]=newCat(i);30:TelepathicFunction();31:}32:33:for(i=0;i<MaxCats;i++)34:{35:deleteCatHouse[i];36:TelepathicFunction();37:}38:return0;39:}40:41:voidTelepathicFunction()42:{43:cout<<"Thereare";44:cout<<Cat::HowManyCats<<"catsalive!\n";45:}Результат:Thereare1catsalive!Thereare2catsalive!Thereare3catsalive!Thereare4catsalive!Thereare5catsalive!Thereare4catsalive!Thereare3catsalive!Thereare2catsalive!Thereare1catsalive!Thereare0catsalive!Анализ: Листинг 14.2 аналогичен листингу 14.1, однако включает новую функциюTelepahicFunction().Она не создает объект СаГ и даже не использует тегов качестве параметра,однако может получить доступ к переменной-члену HowManyCats.