246071-Либерти-Освой-самостоятельно-С-за-21-день (852741), страница 74
Текст из файла (страница 74)
Для создания объекта Edie класса Employee задаются четыре параметра.Для инициализации трех из них задействуются конструкторы класса String, о чемсвидетельствуюттриследующиестрокивывода.Строка 75 информирует о вызове функции SetFirstName. Следующая строка программы,Edie.SetFirstName("Edythe"), создает временный объект класса String из строковой константы"Edythe", для чего вновь задействуются соответствующие конструкторы класса String (см.
6-юстроку вывода). Обратите внимание, что этот временный объект уничтожается сразу же послеприсвоения его значения переменной-члену, о чем свидетельствует вызов деструктора классаString(см.7-юстрокувывода).Присвоивимя,программаприступаеткприсвоениюфамилиислужащего.Этоможнобылобы выполнить так же, как и в случае с присвоением имени с помощью автоматическисоздаваемоговременногообъектаклассаString.Ночтобыпоказатьвсевозможности,встроке78явно создается объект класса String.
Конструктор, создающий этот объект, дал о себе знать 9-йстрокойвывода.Деструкторневызывается,посколькуэтотобъектнеудаляетсядотехпор,поканевыйдетзаграницысвоейобластивидимостивконцефункции.Наконец программа выводит на экран персональные сведения о служащем и выходит заобластьвидимостиобъектаEmployee,врезультатечеговызываютсячетыредеструктораклассадля удаления объектов этого класса, вложенных в объект Employee, и созданного ранеевременногообъектаLastName.ПередачаобъектакакзначенияВ листинге 15.3 показано, как создание одного объекта Employee приводит к вызову пятиконструкторовклассаString.Листинг15.4—этоещеодинпереписанныйвариантпрограммы.Внем нет дополнительных операторов вывода помимо представленных в листинге 15.1 (сейчасони разблокированы) и используется статическая переменная-член ConstructorCount,объявленнаявклассеString.Как следует из объявления в листинге 15.1, значение переменной ConstructorCountувеличивается на единицу при каждом вызове конструктора класса String.
В конце программы,представленной в листинге 15.4, объект Employee передается на печать сначала как ссылка, азатем как значение. Статическая переменная-член ConstructorCount отслеживает, сколькообъектовклассаStringсоздаетсяприразныхспособахпередачиобъектаEmployeeкакпараметрафункции.Примечание:Перед компиляцией этого листинга в программе листинга 15.1дополнительноктемстрокам,которыебылиразблокированыдлялистинга15.3,следуетснятьсимволыкомментариевсострок23,39,52,64,76и153.Листинг15.4.Передачаобъектакакзначения1:#include"String.hpp"2:3:classEmployee4:{5:6:public:7:Employee();8:Employee(char*,char*,char*,long);9:~Employee();10:Employee(constEmployee&);11:Employee&operator=(constEmployee&);12:13:constString&GetFirstName()const14:{returnitsFirstName;}15:constString&GetLastName()const{returnitsLastName;}16:constString&GetAddress()const{returnitsAddress;17:longGetSalary()const{returnitsSalary;}18:19:voidSetFirstName(constString&fName)20:{itsFirstName=fName;}21:voidSetLastName(constString&lName)22:{itsLastName=lName;}23:voidSetAddress(constString&address)24:{itsAddress=address;}25:voidSetSalary(longsalary){itsSalary=salary;}26:private:27:StringitsFirstName;28:StringitsLastName;29:StringitsAddress;30:longitsSalary;31:};32:33:Employee::Employee();34:itsFirstName(""),35:itsLastName(""),36:itsAddress(""),37:itsSalary(0)38:{}39:40:Employee::Employee(char*firstName,char*lastName,41:char*address,longsalary):42:itsFirstName(firstName),43:itsLastName(lastName),44:itsAddress(address),45:itsSalary(salary)46:{}47:48:Employee::Employee(constEmployee&rhs):49:itsFirstName(rhs.GetFirstName()),50:itsLastName(rhs.GetLastName()),51:itsAddress(rhs.GetAddress()),52:itsSalary(rhs.GetSalary())53:{}54:55:Employee::~Employee(){}56:57:Employee&Employee::operator=(constEmployee&rhs)58:{59:if(this==&rhs)60:return*this;61:62:itsFirstName=rhs.GetFirstName();63:itsLastName=rhs.GetLastName();64:itsAddress=rhs.GetAddress();65:itsSalary=rhs.GetSalary();66:67:return*this;68:}69:70:voidPrintFunc(Employee);71:voidrPrintFuno(constEmployee&):72:73:intmain()74:{75:EmployeeEdie("Jane","Doe","1461ShoreParkway",20000);76:Edie.SetSalary(20000);77:Edie.SetFirstName("Edythe");78:StringLastName("Levine");79:Edie.SetLastName(LastName);80:81:cout<<"Constructorcount:";82:cout<<String;:ConstruotorCount<<endl;83:rPrintFunc(Edie);84:cout<<"Constructorcount:";85:cout<<String::ConstructorCount<<endl;86:PrintFunc(Edie);87:cout<<"Constructorcount:";88:cout<<String::ConstructorCount<<endl;89:return0;90:}91:voidPrintFunc(EmployeeEdie)92:{93:94:cout<<"Name:";95:cout<<Edie.GetFirstName().GetString();96:cout<<""<<Edie.GetLastName().GetString();97:cout<<".\nAddress:";98:cout<<Edie.GetAddress().GetString();99:cout<<".\nSalary:";100:cout<<Edie.GetSalary();101:cout<<endl;102:103:}104:105:voidrPrintFunc(constEmployee&Edie)106:{107:cout<<"Name:";108:cout<<Edie.GetFirstName().GetString();109:cout<<""<<Edie.GetLastName().GetString();110:cout<<"\nAddress:";111:cout<<Edie.GetAddress().GetString();112:cout<<"\nSalary:";113:cout<<Edie.GetSalary();114:cout<<endl;115:}Результат:String(char*)constructorString(char*)constructorString(char*)constructorString(char*)constructorStringdestructorString(char*)constructorConstructorcount:5Name:EdytheLevineAddress:1461ShoreParkwaySalary:20000Constructorcount;5String(String&)constructorString(String&)constructorString(String&)constructorName:EdytheLevineAddress:1461ShoreParkwaySalary:20000StringdestructorStringdestructorStringdestructorConstructorcount:8StringdestructorStringdestructorStringdestructorStringdestructorАнализ: Как видно по данным, выводимым программой, в процессе создания одногообъекта Employee создается пять объектов класса String.
Когда объект Employee передается вфункцию rPrintFunc() как ссылка, дополнительные объекты Employee не создаются.Соответственно не создаются и дополнительные объекты String. (Все они, кстати, такжеавтоматическипередаютсякакссылки.)Когда объект Employee передается в функцию PrintFunc() как значение, создается копияобъектаEmployeeвместестремяобъектамиклассаString(дляэтогоиспользуетсяконструкторкопировщик).РазличныепутипередачифункциональностиклассуВ некоторых случаях одному классу необходимо передать некоторые свойства другого.Предположим, например, что вам необходимо создать класс каталога деталей PartsCatalog.
Наоснове класса PartsCatalog предполагается создать коллекцию объектов, представляющуюразличные запчасти с уникальными номерами. В базе данных на основе класса PartsCatalogзапрещается дублирование объектов, а для доступа к объекту необходимо указать егоидентификационныйномер.Ранее, в обзоре за вторую неделю, уже был объявлен и детально проанализирован классPartsList. Чтобы не начинать работу с нуля, можно взять этот класс за основу при объявлениикласса PartsCatalog. Для этого можно вложить класс PartsList в класс PartsCatalog, чтобы затемделегировать классу PartsCatalog ответственность за поддержание связанного списка в классPartsList.Существуетальтернативныйпуть.МожнопроизвестиклассPartsCatalogотклассаPartsList,таким образом унаследовав все свойства последнего. Помните однако, что открытоенаследование (со спецификатором public) предполагает логическую принадлежностьпроизводного класса более общему базовому классу.
Действительно ли в нашем случае классPartsCatalog является частным проявлением класса PartList? Чтобы разобраться в этом,попробуйтеответитьнарядвопросов.1.СодержитлибазовыйклассPartsListметоды,неприменимыевклассеPartsCatalog?Еслида,то,вероятно,ототкрытогонаследованиялучшеотказаться.2.БудетлиодинобъектклассаPartsCatalogсоответствоватьодномуобъектуклассаPartsList?Если для создания объекта требуется не менее двух объектов PartsList, то, безусловно,необходимоприменятьвложение.3. Обеспечит ли наследование от базового класса преимущества в работе благодаряиспользованию виртуальных функций или методов доступа к защищенным членам базовогокласса?Вслучаеположительногоответаимеетсмыслвоспользоватьсяоткрытымилизакрытымнаследованием.Ответивнаприведенныевышевопросы,выдолжныпринятьрешение,использоватьливамв программе открытое наследование, закрытое наследование (см.
далее в этом занятии) иливложение.Познакомимсяснекоторымитерминами,которыепотребуютсянампридальнейшемобсужденииэтойтемы.•Вложение—объект,относящийсякдругомуклассу,используетсявтекущийкласс.• Делегирование — передача ответственности за выполнение специальных функцийвложенномуклассу.• Выполнение средствами класса — реализация специальных функций в классе за счетдругогоклассабезиспользованияоткрытогонаследования.ДелегированиеПочему же класс PartsCatalog нельзя произвести от PartsList? Дело в том, что классPartsCatalogдолженобладатьсовершенноинымисвойствамииeroневозможнопредставитькакчастную реализацию класса PartsList.
Посмотрите, класс PartsList — это коллекция объектов,упорядоченная по возрастанию номеров, элементы которой могут повторяться. КлассPartsCatalogпредставляетнеупорядоченнуюколлекциюуникальныхобъектов.Конечно, при желании можно произвести класс PartsList от класса PartsList соспецификатором public, после чего соответствующим образом заместить функцию Insert() иоператориндексирования([]).Однакотакиедействиякрайненелогичныипротиворечатсамойсути наследования. Вместо этого следует создать новый класс PartsCatalog, в котором нетоператораиндексирования,неразрешаетсядублированиезаписейиперегружаетсяoperator+длясуммирования наборов записей.