246071-Либерти-Освой-самостоятельно-С-за-21-день (852741), страница 50
Текст из файла (страница 50)
В тех классах, где в числе членовкласса используются указатели на области динамической памяти, вместо поверхностногокопирования лучше использовать глубинное, при котором копируемые данные размещаются поновымадресам.Хотя в языке C++ можно произвольно перегружать все операторы, настоятельнорекомендуемнесоздаватьтакихоператоров,функциикоторыхпротиворечатихтрадиционномуиспользованию. Кроме того, невозможно изменить ассоциативность оператора, а такжесоздаватьсобственныеоператоры,непредставленныевязыкеC++.Указатель this ссылается на текущий объект и является невидимым параметром для всехфункций-членов.
Разыменованный указатель this часто возвращается перегруженнымиоператорами.Операторы преобразования типов позволяют настраивать классы для использования ввыражениях, осуществляющих обмен данными разных типов. Данные операторы являютсяисключениемизправила,состоящеговтом,чтовсефункциивозвращаютявныезначения,как,например,конструкторидеструктор.Вданныхоператорахтипвозвратанеустанавливается.ВопросыиответыЗачемиспользоватьзначения,заданныепоумолчанию,еслиможноперегрузитьфункцию?Проще иметь дело с одной функцией, чем с двумя.
Кроме того, зачастую проще понятьработуфункции,использующейзначения,заданныепоумолчанию,чемкаждыйразвнимательноизучать тело функции, чтобы понять ее назначение. Кроме того, обновление одной версиифункциибезобновлениядругойверсиичастобываетпричинойошибоквработепрограммы.Почемубытогдапостояннонеиспользоватьтолькозначения,заданныепоумолчанию?Перегрузка функций предоставляет ряд возможностей, которые нельзя реализовать,используя только значения, заданные по умолчанию. Например, изменять не только числопараметроввсписке,ноиихтипы.Какие переменные-члены следует инициализировать одновременно с инициализациейконструктора,акакиеоставлятьдлятелаконструктора?Используйте следующее простое правило: одновременно с конструктором следуетинициализировать как можно больше переменных-членов. Только некоторые из них, такие какпеременные для текущих вычислений и управления выводом на печать следуетинициализироватьвтелеконструктора.Можетлиперегруженнаяфункциясодержатьпараметры,заданныепоумолчанию?Конечно.
Нет никакой причины, по которой не следовало бы использовать это мощноесредство. Одна или несколько версий перегруженных функций могут иметь собственныезначения, заданные по умолчанию. При установке значений по умолчанию для перегруженныхфункцийнужноследоватьтемжеобщимправилам,чтоиприустановкезначенийпоумолчаниюдляобычныхфункций.Почемуоднифункции-членыопределяютсявописаниикласса,адругиенет?Еслифункцияопределяетсявописаниикласса,тодалееонаиспользуетсяврежимеinline.Впрочем,встраиваниекодафункциипоместувызовапроисходиттольковтом случае, если функция достаточно простая. Также следует отметить, что задатьвстраивание кода функции-члена в код программы можно с помощью ключевого слова inline,дажееслиэтафункциябылаописанаотдельнооткласса.КоллоквиумВэтомразделепредлагаютсявопросыдлясамоконтроляиукрепленияполученныхзнанийи приводится несколько упражнений, которые помогут закрепить ваши практические навыки.Попытайтесьсамостоятельноответитьнавопросытестаивыполнитьзадания,апотомсверьтеполученные результаты с ответами в приложении Г.
Не приступайте к изучению материаласледующей главы, если для вас остались неясными хотя бы некоторые из предложенных нижевопросов.Контрольныевопросы1.Есливыперегрузилифункцию-член,какпотомможнобудетразличитьразныевариантыфункции?2.Какаяразницамеждуопределениемиобъявлением?3.Когдавызываетсяконструктор-копировщик?4.Когдавызываетсядеструктор?5.Чемотличаетсяконструктор-копировщикотоператораприсваивания(=)?6.Чтопредставляетсобойуказательthis?7.Какотличаетсяперегрузкаоператоровпредварительногоипоследующегодействия?8.Можнолиперегрузитьoperator+дляпеременныхтипаshortint?9.ДопускаетсяливC++перегрузкаoperator++такимобразом,чтобыонвыполнялвклассеоперациюдекремента?10.
Как устанавливается тип возврата в объявлениях функций операторов преобразованиятипов?Упражнения1.ПредставьтеобъявлениеклассаSimpleCircleсединственнойпеременой-членомitsRadius.В классе должны использоваться конструктор и деструктор, заданные по умолчанию, а такжеметодустановкирадиуса.2. Используя класс, созданный в упражнении 1, с помощью конструктора, заданного поумолчанию,инициализируйтепеременнуюitsRadiusзначением5.3.
Добавьте в класс новый конструктор, который присваивает значение своего параметрапеременнойitsRadius.4. Перегрузите операторы преинкремента и постинкремента для использования в вашемклассеSimpleCircleспеременнойitsRadius.5.ИзменитеSimpleCircleтакимобразом,чтобысохранятьitsRadiusвдинамическойобластипамятиификсироватьсуществующиеметоды.6.СоздайтевклассеSimpleCircleконструктор-копировщик.7.ПерегрузитевклассеSimpleCircleоператорприсваивания.8. Напишите программу, которая создает два объекта класса SimpleCircle. Для созданияодного объекта используйте конструктор, заданный по умолчанию, а второму экземпляру приобъявлении присвойте значение 9.
С каждым из объектов используйте оператор инкремента ивыведитеполученныезначениянапечать.Наконец,присвойтезначениеодногообъектадругомуобъектуивыведитерезультатнапечать.9.Жучки:чтонеправильновследующемпримереиспользованияоператораприсваивания?SQUARESQUARE::operator=(constSQARE&rhs){itsSide=newint;*itsSide=rgs.GetSide();return<<this;}10. Жучки: что неправильно в следующем примере использования операторасуммирования?VeryShortVeryShort::operator+(constVeryShort&rhs){itsval+=rhs.GetItsVal();return*this;}День11-й.Наследование Фундаментальной основой человеческого мышления является поиск, выявление ипостроениевзаимоотношениймеждуразличнымиконцепциями.Чтобыпостичьхитросплетенияотношений между вещами и явлениями, мы используем иерархические построения, матрицы,сетиипрочиесредствавизуализации.Чтобылучшевыразитьсутьотношениймеждуобъектами,вC++используетсяиерархическаясистеманаследования.Сегоднявыузнаете:•Чтопредставляетсобойнаследование•Какпроизвестиодинклассиздругого•Чтотакоезащищенныйдоступикакегоиспользовать•ЧтотакоевиртуальныефункцииЧтотакоенаследованиеЧтотакоесобака?Чтовывидите,когдасмотритенасвоегопитомца?Явижучетырелапы,обслуживающиезубастуюпасть.Биологувидитсистемувзаимодействующихорганов,физик—стройную систему атомов и совокупность разных видов энергии, а ученый, занимающийсясистематикоймлекопитающих,—типичногопредставителявидаCanisfamiliaris.Каждый смотрит на объект со своей точки зрения, но сегодня нас будет интересоватьпоследнее утверждение, а именно: собака является представителем семейства волчьих, классамлекопитающих и т.д.
С точки зрения систематики любой объект живой природырассматриваетсявпланепринадлежностиоднойсистемеиерархическихтаксонов:царству,типу,классу,отряду,семейству,родуивиду.Иерархия представляет собой вид отношений подчиненности типа принадлежностичастного общему. Так, человек является видом приматов. Подобный тип отношений можновидеть повсюду. Грузовик является видом машин, а машина, в свою очередь, является видомтранспортных средств. Пирожное является видом сладких блюд, а сладкие блюда являютсявидомпищи.Когда мы говорим, что нечто является видом чего-то, то подразумеваем большуюдетализацию объявления объекта.
Так, отмечая, что машина — это вид транспортных средств,мы из всевозможных средств передвижения (от повозки до самолета) выбираем толькочетырехколесныеустройствасдвигателем.Иерархияинаследование Говоря о собаке, как представителе класса млекопитающих, мы подразумеваем, что онанаследует все признаки, общие для класса млекопитающих. Поскольку собака —млекопитающее, можно предположить, что это подвижный вид животных, дышащих воздухом.Все млекопитающие по определению двигаются и дышат воздухом.
Если определить некийобъект как собаку, это добавит к объявлению способность вилять хвостом, грызть рукописькниги,которуюякакразсобралсянестивредакцию,бегатьподомуилаять,когдаясплю...оизвините,кудаменязанесло!Нутаквот,продолжим.В свою очередь, собак можно разделить на служебных, спортивных и охотничьих. Потомможнопойтидальшеиописатьпородусобаки:спаниель,лабрадорит.д.Таким образом, мы можем сказать, например, что фокстерьер — это порода охотничьихсобак, в которой представлены все признаки, общие для собак вообще, а также все признаки,общие для млекопитающих и т.д., включая признаки всех таксонов, к которым относитсяфокстерьер.
Пример такой иерархии показан на рис. 11.1, где стрелками связаны категорииболеенизкогоуровняскатегориямследующегопорядка.Рис.11.1.ИерархиямлекопитающихВC++иерархичностьреализованавконцепцииклассов,гдеодинклассможетпроисходить,или наследоваться от класса более высокого уровня. В наследовании классов реализуютсяпринципы их иерархической подчиненности. Предположим, мы производим новый класс Dog(Собака) от класса Mammal (Млекопитающее).
Другими словами, класс Mammal являетсябазовым для класса Dog. Точно так же, как описание вида собака несет в себе признаки,детализирующие описание млекопитающих в целом, так и класс Dog содержит ряд методов иданных,дополняющихметодыиданные,которыепредставленывклассеMammal.Как правило, с базовым классом связано несколько производных классов. Посколькусобаки, кошки и лошади являются представителями млекопитающих, то с точки зрения C++можносказать,чтовсеэтиклассыпроизведеныотклассаMammal.ЦарствоживотныхЧтобы более наглядно раскрыть смысл наследования классов, рассмотрим эту тему напримере отношений между многочисленными представителями животного мира. Представимсебе,чтопрограммисту,поступилзаказнасозданиедетскойигры"Ферма".Когдавыприступитексозданиюживотных,обитающихнаферме,включаялошадей,коров,собак, кошек, овец и т.д., вам потребуется снабдить каждый их класс такими методами,благодаря которым они смогут вести себя на экране так, как этого ожидает ребенок.
Но наданном этапе каждый метод снабжен только функцией вывода на печать. Это общая практикапрограммирования, когда сначала выполняется только формулировка набора методов, адетальная проработка их откладывается на потом. Вы вправе использовать все примерыпрограмм, приведенные в этой главе, как основу для дальнейшей доработки с тем, чтобы всеживотныевелисебятак,каквамхочется.СинтаксиснаследованияклассовДля создания нового производного класса используется ключевое слово class, послекоторого указывается имя нового класса, двоеточие, тип объявления класса (public или какойнибудьдругой),азатемимябазовогокласса,каквследующемпримере:classDog:publicMammalТипынаследованияклассоврассматриваютсядалеевэтойкниге.Покабудемиспользоватьтолько открытое наследование. Класс, из которого производится новый класс, должен бытьобъявлен раньше, иначе компилятор покажет сообщение об ошибке.