246071-Либерти-Освой-самостоятельно-С-за-21-день (852741), страница 73
Текст из файла (страница 73)
В этомслучае программисты на C++ говорят, что внешний класс содержит внутренний. Так, классEmployee в качестве переменных-членов может содержать строковые объекты (с именемсотрудника)иобъектысцелочисленнымизначениями(зарплатойит.д.).Влистинге15.1представленнезавершенный,новесьмаполезныйклассString.Запусктакойпрограммы не приведет к выводу каких-либо результатов, но она потребуется при написаниидругихпрограммэтогозанятия.Листинг15.1.Классstring1:#include<iostream.h>2:#include<string.h>3:4:classString5:{6:public:7://конструкторы8:String();9:String(constchar*const);10:String(constString&)11:~String();12:13://перегруженныеоператоры14:char&operator[](intoffset);15:charoperator[](intoffset)const;16:Stringoperator+(constString&);17:voidoperator+=(constString&);18:String&operator=(constString&);19:20://Общиеметодыдоступа21:intGetLen()const{returnitsLen;}22:constchar*GetString()const{returnitsString;}23://статическийцелочисленныйсчетчикConstructorCount;24:25:private:26:String(int);//закрытыйконструктор27:char*itsString;28:unsignedshortitsLen;29:30:};31:32://конструкторклассаStringпoумолчаниюсоздаетстрокудлиной0байт33:String::String()34:{35:itsString=newchar[1];36:itsString[0]='\0';37:itsLen=0;38://cout<<"\tDefaultstringconstructor\n";39://ConstructorCount++;40:}41:42://закрытыйконструктор,используемыйтолько43://методамиклаcсадлясозданияновойcтроки44://указанногоразмера,заполненнойнулями45:String::String(intlen)46:{47:itsString=newohar[len+1];48:for(inti=0;i<=len;i++)49:itsString[i]='\0';50:itsLen=len;51://cout<<"\tString(int)constructor\n";52://ConstructorCount++;53:}54:55://Преобразуетмассивсимволоввcтроку56:String::String(constchar*oonstcString)57:{58:itsLen=strlen(cString);59:itsString=newchar[itsLen+1];60:for(inti=0;i<itsLen;i++)61:itsString[i]=cString[i];62:itsString[itsLen]='\0';63://cout<<"\tString(char*)constructor\n";64://ConstructorCount++;65:}66:67://конструктор-копировщик68:String::String(constString&rhs)69:{70:itsLen=rhs.GetLen();71:itsString=newchar[itsLen+1];72:for(inti=0;i<itsLen;i++)73:itsString[i]=rhs[i];74:itsString[itsLen]='\0';75://cout<<"\tString(String&)constructor\n76://ConstructorCount++;77:}78:79://деструкторосвобождаетзанятуюпамять80:String::~String()81:{82:delete[]itsString;83:itsLen=0;84://cout<<"\tStringdestructor\n";85:}86:87://этотоператоросвобождаетпамять,азатем88://копируетстрокуиразмер89:String&String::operator=(constString&rhs)90:{91:if(this==&rhs)92:return*this;93:delete[]itsString;94:itsLen=rhs.GetLen();95:itsString=newchar[itsLen+1];96:for(inti=0;i<itsLen;i++)97:itsString[i]=rhs[i];98:itsString[itsLen]='\0';99:return*this;100://cout<<"\tStringoperator=\n";101:}102:103://неконстантныйоператориндексирования,104://возвращаетссылкунасимвол,которыйможно105://изменить106:char&String::operator[](intoffset)107:{108:if(offset>itsLen)109:returnitsString[itsLen-1];110:else111:returnitsStnng[offset];112:}113:114://константныйоператориндексирования,115://используетсядляконстантныхобъектов(см.конструктор-копировщик!)116:charString::operator[](intoffset)const117:{118:if(offset>itsLen)119:returnitsString[itsLen-1];120:else121:returnitsString[offset];122:}123:124://создаетновуюстроку,добавляятекущую125://строкукrhs126:StringString::operator+(constString&rhs)127:{128:inttotalLen=itsLen+rhs.GetLen();129:Stringtemp(totalLen);130:inti,j;131:for(i=0;i<itsLen;i++)132:temp[i]=itsString[i];133:for(j=0:j<rhs.GetLen();j++,i++)134:temp[i]=rhs[j];135:temp[totalLen]='\0';136:returntemp;137:}138:139://изменяеттекущуюстроку,ничегоневозвращая140:voidString::operator+=(constString&rhs)141:{142:unsignedshortrhsLen=rhs.GetLen();143:unsignedshorttotalLen=itsLen+rhsLen;144:Stringtemp(totalLen);145:inti,j;146:for(i=0;i<itsLen;i++)147:temp[i]=itsString[i];148:for(j=0;j<rhs.GetLen();j++,i++)149:temp[i]=rhs[i-itsLen];150:temp[totalLen]='\0';151:*this=temp;152:}153:154://intString::ConstructorCount=0;Результат:НетАнализ: Представленный в листинге 15.1 класс String напоминает другой класс,использованный в листинге 12.12.
Однако есть одно важное отличие между этими двумяклассами: конструкторы и некоторые функции листинга 12.12 включали операторы вывода напечать,благодарякоторымнаэкранеотображалисьсообщенияобихиспользовании.Влистинге15.1 эти операторы временно заблокированы, но они будут использоваться в следующихпримерах.Статическая переменная-член ConstructorCount объявляется и инициализируетсясоответственно в строках 23 и 154.
Значение этой переменной увеличивается на единицу привызове любого конструктора класса String. Эти функции также заблокированы и будутиспользоватьсявследующихлистингах.Влистинге15.2объявляетсяклассEmployee,содержащийтриобъектаклассаString.Листинг15.2.КлассEmployee1:#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&fNama)20:{itsFirstName=fName;}21:voidSetLastName(constString&lNama)22:{itsLastName=lNamo;}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::~Employea(){}56:57:Employee&Employae::Qperator=(constEmployee&rhs)58:{59:if(thls—&rhs)60:return*this;61:62:itsFlrstName=rhs.GetFlrstName();63:itsLastName=rhs,GetLastName();64:itsAddress=rhs,GetAddress();65:itsSalary=rhs,GetSalary();66:67:return*thls;68:}69:70:intmain()71:{72:EmployeeEdie("Jane","Doe","1461ShoreParkway",20000);73:Edie.SetSalary(50000);74:StringLastName("Levine");75:Edie.SetLastName(LastName);76:Edie.SetFirstName("Edythe");77:78:cout<<"Имя:";79:cout<<Edie.GetFirstName().GetString();80:cout<<""<<Edie.GetLastName().GetString();81:cout<<".\nАдрес:";82:cout<<Edie.GetAddress().GetString();83:cout<<".\nЗарплата:";84:cout<<Edie.GetSalary();85:return0;86:}Примечание:Сохраните листинг 15.1 в файле с именем string.
hpp. Затем всякий раз,когда понадобится класс String, вы сможете вставить листинг 15.1, просто добавив строку#include"String.hpp".Этоперваястрокавлистинге15.2.Результат:Name:EdytheLevine.Address:1461ShoreParkway.Salary:50000Анализ: В листинге 15.2 объявляется класс Employee, переменными-членами котороговыступаюттриобъектаклассаString—itsFirstName,itsLastNameиitsAddress.Встроке72создаетсяобъектEmployee,которыйинициализируетсячетырьмязначениями.Встроке73вызываетсяметоддоступаSetSalaryклассаEmployee,которыйпринимаетконстантноезначение 50000. В реальной программе это значение определялось бы либо динамически впроцессевыполненияпрограммы,либоустанавливалосьбыконстантой.В строке 74 создается и инициализируется строковой константой объект класса String,которыйвстроке75используетсявкачествеаргументафункцииSetLastName().В строке 76 вызывается метод SetFirstName класса Employee с еще одной строковойконстантойвкачествепараметра.ОднакоесливыобратитеськобъявлениюклассаEmployee,тоувидите, что в нем нет функции SetFirstName(), принимающей строку символов как аргумент.Для функции SetFirstName() в качестве параметра задана константная ссылка на объект String.Темнеменеекомпиляторнепокажетсообщенияобошибке,посколькувстроке9листинга15.1объявленконструктор,создающийобъектStringизстроковойконстанты.ДоступкчленамвложенногоклассаВ классе Employee не объявлены специальные методы доступа к переменным- членамклассаString.ЕслиобъектEdieклассаEmployeeпопытаетсянапрямуюобратитьсякпеременнойчлену itsLen, содержащейся в ero собственной переменной- члене itsFirstName, это приведет квозникновению ошибки компиляции.
Однако в таком обращении нет необходимости. Методыдоступа класса Employee просто создают интерфейс для класса String, и классу Employee нетнужды беспокоиться о деталях выполнения класса String, а также о том, каким образомсобственнаяцелочисленнаяпеременная-членitsSalaryхранитсвоезначение.ФильтрациядоступаквложеннымклассамВы,наверное,ужезаметили,чтовклассеStringперегружаетсяoperator+.ВклассеEmployeeдоступ к перегруженной функции operator+ заблокирован. Дело в том, что в объявленияхметодов доступа класса Employee указано, что все эти методы, такие как GetFirstName(),возвращают константные ссылки. Поскольку функция operator+ не является (и не может быть)константой (она изменяет объект, для которого вызывается), попытка написать следующуюстрокуприведетксообщениюобошибкекомпиляции:Stringbuffer=Edie.GetFirstName()+Edie.GetLastName();Функция GetFirstName() возвращает константную строку и вы не можете использоватьoperator+сконстантнымобъектом.Чтобы устранить эту проблему, следует перегрузить функцию GetFirstName() такимобразом,чтобыонасталанеконстантной:constString&GetFirstName()const{returnitsFirstName;}String&GetFirstName(){returnitsFirstName;}Как видите, возвращаемое значение больше не является константой, также как и самафункция-член.
Изменения возвращаемого значения недостаточно для перегрузки именифункции.Необходимоизменитьконстантностьсамойфункции.ЦенавложенийВажноотметить,чтопользователюпридется"расплачиваться"закаждыйобъектвнешнегоклассавсякийразприсозданиииликопированииобъектаEmployee.Снимитесимволыкомментариевсоператоровcoutлистинга15.1(строки38,51,63,75,84и100),ивыувидите,какчастоонивызываются.Влистинге15.3представленатажепрограмма,что и в листинге 15.2, только в этом примере добавлены операторы печати, которые будутпоказыватьсообщениянаэкраневсякийразпривыполненииконструктораклассаEmployee.Этопозволитнаглядноувидетьвесьпроцесссозданияобъектоввпрограмме.Примечание:Докомпиляцииэтоголистингаразблокируйтестроки38,51,63,75,84и100влистинге15.1.Листинг15.3.Конструкторывложенныхклассов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:itsAddrsss(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:intmain()71:{72:cout<<"CreatingEdie...\n";73:EmployeeEdie("Jane","Doe","1461ShoreParkway",20000);74:Edie,SetSalary(20000);75:cout<<"CallingSetFirstNamewithchar*...\n";76:Edie,SetFirstName("Edythe");77:cout<<"CreatingtemporarystringLastName...\n";78:StringLastName("Levine");79:Edis,SetLastName(LastName);80:81:cout<<"Name:";82:cout<<Edle.QetFirstName().GetString();83:cout<<""<<Edie,GstLastName().GitString();84:cout<<"\nAddress;";85:cout<<Edi6.GetAddress(),GetString();86:cout<<"\nSalary;";87:cout<<Edie.GstSalary();88:cout<<endl;89:return0;90:}Результат:CreatingEdie...String(char*)constructorString(char*)constructorString(char*)constructorCallingSetFirstNamewithchar*...String(char*)constructorStringdestructorCreatingtemporarystringLastName...String(char*)constructorName:EdytheLevineAddress:1461ShoreParkwaySalary:20000StringdestructorStringdestructorStringdestructorStringdestructorАнализ:Влистинге15.3используютсяклассы,объявленныеранеевлистингах15.1и15.2.Единственноеотличиесостоитвтом,чтооператорыcoutразблокированы.Чтобыупроститьобсуждение,строки,выводимыепрограммойнаэкран,былипронумерованы.В строке 72 листинга 15.3 выводится сообщение Creating Edie..., которому соответствуетпервая строка вывода.