246071-Либерти-Освой-самостоятельно-С-за-21-день (852741), страница 97
Текст из файла (страница 97)
Это объявление означает, что каждый экземпляр массива типа int будетсчитатьфункциюIntrude()дружественной,аследовательно,онабудетиметьдоступкзакрытымпеременным-членамифункциям-членамэкземпляраэтогомассива.В строке 60 функция lntrude() непосредственно обращается к члену itsSize, а в строке 61получает прямой доступ к переменной-члену pType. В данном случае без использованияфункции-друга можно было бы обойтись, поскольку класс Array предоставляет открытыеметоды доступа к этим данным. Этот листинг служит лишь примером того, как можнообъявлятьииспользоватьфункции-друзьяшаблонов.ДружественныйклассилифункциякакобщийшаблонВ класс Array было бы весьма полезно добавить оператор вывода данных.
Это можносделать путем объявления оператора вывода для каждого возможного типа массива, но такойподходсвелбыненетсамуидеюиспользованияклассаArrayкакшаблона.Поэтому нужно найти другое решение. Попробуем добиться того, чтобы оператор выводаработалнезависимооттипаэкземплярамассива.ostream&operator<<(ostream&,Array<T>&);Чтобы этот оператор работал, нужно так объявить operator<<, чтобы он стал функциейшаблона:template<classT>ostream&operator<<(ostream&,Array<T>&)Теперь operator<< является функцией шаблона и его можно использовать в выполнениикласса.Влистинге19.4показанообъявлениешаблонаArray,дополненноеобъявлениемфункцииоператоравыводаoperator<<.Листинг18.4.Использованиеоператоравывода1:#include<iostream.h>2:3:constintDefaultSize=10;4:5:classAnimal6:{7:public:8:Animal(int);9:Animal();10:~Animal(){}11:intGetWeight()const{returnitsWeight;}12:voidDisplay()const{cout<<itsWeight;}13:private:14:intitsWeight;15:};16:17:Animal::Animal(intweight):18:itsWeight(weight)19:{}20:21:Animal::Animal():22:itsWeight(0)23:{}24:25:template<classT>//объявляемшаблонипараметр26:classArray//параметризованныйкласс27:{28:public:29://конструкторы30:Array(intitsSize=DefaultSize);31:Array(constArray&rhs);32:~Array(){delete[]pType;}33:34://операторы35:Array&operator=(constArray&);36:T&operator[](intoffSet){returnpType[offSet];}37:constT&operator[](intoffSet)const38:{returnpType[offSet];}39://методыдоступа40:intGetSize()const{returnitsSize;}41:42:friendostream&operator<<(ostream&,Array<T>&);43:44:private:45:T*pType;46:intitsSize;47:};48:49:template<classT>50:ostream&operator<<(ostream&output,Array<T>&theArray)51:{52:for(inti=0;i<theArray.GetSize();i++)53:output<<"["<<i<<"]"<<theArray[i]<<endl;returnoutput;54:}55:56://Рядвыполнений...57:58://выполнениеконструктора59:template<classT>60:Array<T>::Array(intsize):61:itsSize(size)62:{63:pType=newT[size];64:for(inti=0;i<size;i++)65:pType[i]=0;66:}67:68://конструктор-копировщик69:template<classT>70:Array<T>::Array(constArray&rhs)71:{72:itsSize=rhs.GetSize();73:pType=newT[itsSize];74:for(inti=0;i<itsSize;i++)75:pType[i]=rhs[i];76:}77:78://перегрузкаоператораприсваивания(=)79:template<classT>80:Array<T>&Array<T>::operator=(constArray&rhs)81:{82:if(this==&rhs)83:return*this;84:delete[]pType;85:itsSize=rhs.GetSize();86:pType=newT[itsSize];87:for(inti=0;i<itsSize;i++)88:pType[i]=rhs[i];89:return*this;90:}91:92:intmain()93:{94:boolStop=false;//признакдляцикла95:intoffset,value;96:Array<int>theArray;97:98:while(!Stop)99:{100:cout<<"Enteranoffset(0-9)";101:cout<<"andavalue.(-1tostop):";102:cin>>offset>>value;103:104:if(offset<0)105:break;106:107:if(offset>9)108:{109:cout<<"***Pleaseusevaluesbetween0and9.***\n";110:continue;111:}112:113:theArray[offset]=value;114:}115:116:cout<<"\nHere'stheentirearray:\n";117:cout<<theArray<<endl;118:return0;119:}Результат:Enteranoffset(0-9andаvalue.(-1tostop)110Enteranoffset(0-9andаvalue.(-1tostop)220Enteranoffset(0-9andаvalue.(-1tostop)330Enteranoffset(0-9andаvalue.(-1tostop)440Enteranoffset(0-9andаvalue.(-1tostop)550Enteranoffset(0-9andаvalue.(-1tostop)660Enteranoffset(0-9andаvalue.(-1tostop)770Enteranoffset(0-9andаvalue.(-1tostop)880Enteranoffset(0-9andаvalue.(-1tostop)990Enteranoffset(0-9andаvalue.(-1tostop)1С10***Pleaseusevaluesbetween0and9.*>>*Enteranoffset(0-9)andаvalue.(-1tostop)-1-1Here'stheentirearray:[0]0[1]10[2]20[3]30[4]40[5]50[6]60[7]70[8]80[9]90Анализ: В строке 42 объявляется шаблон функции operator<<() в качестве друга шаблонаклассаArray.Посколькуoperator<<()реализованввидефункциишаблона,токаждыйэкземплярэтого типа параметризованного массива будет автоматически иметь функцию operator<<() длявывода данных соответствующего типа.
Выполнение этого оператора начинается в строке 49.Каждый член массива вызывается по очереди. Этот метод работает только в том случае, еслифункцияoperator<<()определенадлякаждоготипаобъекта,сохраняемоговмассиве.ИспользованиеэкземпляровшаблонаСэкземплярамишаблонаможнообращатьсятакже,какслюбымидругимитипамиданных.Их можно передавать в функции как ссылки или как значения и возвращать как результатвыполнения функции (тоже как ссылки или как значения). Способы передачи экземпляровшаблонапоказанывлистинге19.5.Листинг19.5.Передачавфункциюэкземплярашаблона1:#include<iostream.h>2:3:constintDefaultSize=10;4:5://Обычныйкласс,изобъектовкоторогобудетсостоятьмассив6:classAnimal7:{8:public:9://конструкторы10:Animal(int);11:Animal();12:~Animal();13:14://методыдоступа15:intGetWeight()const{returnitsWeight;}16:voidSetWeight(inttheWeight){itsWeight=theWeight;}17:18://дружественныеоператоры19:friendostream&operator<<(ostream&,constAnimal&);20:21:private:22:intitsWeight;23:};24:25://операторвыводаобъектовтипаAnimal26:ostream&operator<<27:(ostream&theStream,constAnimal&theAnimal)28:{29:theStream<<theAnimal.GetWeight();30:returntheStream;31:}32:33:Animal::Animal(intweight):34:itsWeight(weight)35:{36://cout<<"Animal(int)\n";37:}38:39:Animal::Animal():40:itsWeight(0)41:{42://cout<<"Animal()\n";43:}44:45:Animal::~Animal()46:{47://cout<<"Destroyedananimal...\n";48:}49:50:template<classT>//объявлениешаблонаипараметра51:classArray//параметризованныйкласс52:{53:public:54:Array(intitsSlze=DefaultSize);55:Array(constArray&rhs);56:~Array(){delete[]pType;}57:56:Array&operator=(constArray&);59:T&operator[](intoffSet){returnpType[offSet];}60:constT&operator[](intoffSet)const61:{returnpType[offSet];}62:intGetSize()const{returnitsSize;}63:64://функция-друг65:friendostream&operator<<(ostream&,constArray<T>&);66:67:private:68:T*рТуре;69:intitsSize;70:};71:70:template<classT>72:ostream&operator<<(ostream&output,constArray<T>&theArray)73:{74:for(inti=0;i<theArray.GetSize();i++)75:output<<"["<<i<<"]"<<theArray[i]<<endl;76:returnoutput;77:}78:79://Рядвыполнений...80:81://выполнениеконструктора82:template<classT>83:Array<T>::Array(intsize):84:itsSize(size)85:{86:рТуре=newT[size];67:for(inti=0;i<size;i++)88:pType[i]=0;89:}90:91://конструктор-копировщик92:template<classT>93:Array<T>::Array(constArray&rhs)94:{95:itsSize=rhs.GetSize();96:рТуре=newT[itsSize];97:for(inti=0;i<itsSize;i++)98:pType[i]=rhs[i];99:}100:101:voidIntFillFunction(Array<int>&theArray);102:voidAnimalFillFunction(Array<Animal>&theArray);103:104:intmain()105:{106:Array<int>intArray;107:Array<Animal>animalArray;108:IntFillFunction(intArray);109:AnimalFillFunction(animalArray);110:cout<<"intArray...\n"<<intArray;111:cout<<"\nanimalArray...\n"<<aninalArray<<endl;112:return0;113:}114:115:voidIntFillFunction(Array<int>&theArray)116:{117:boolStop=false;118:intoffset,value;119:while(!Stop)120:{121:cout<<"Enteranoffset(0-9)";122:cout<<"andavalue,(-1tostop):";123:cin>>offset>>value;124:if(offset<0)125:break;126:if(offset>9)127:{128:cout<<"***Pleaseusevaluesbetween0and9.***\n";129:continue;130:}131:theArray[offset]=value;132:}133:}134:135:136:voidAnimalFillFunction(Array<Animal>&theArray)137:{138:Animal*pAnimal;139:for(inti=0;i<theArray,GetSize();i++)140:{141:pAnimal=newAnimal;142:pAnimal->SetWeight(i*100);143:theArray[i]=*pAnimal;144:deletepAnimal;//копиябылапомещенавмассив145:}146:}Результат:Enteranoffset(0-9)andаvalue.(-1tostop)110Enteranoffset(0-9)andаvalue.(-1tostop)220Enteranoffset(0-9)andаvalue.(-1tostop)330Enteranoffset(0-9)andаvalue.(-1tostop)440Enteranoffset(0-9)andаvalue.(-1tostop)550Enteranoffset(0-9)andаvalue.(-1tostop)660Enteranoffset(0-9)andаvalue.(-1tostop)770Enteranoffset(0-9)andаvalue.(-1tostop)880Enteranoffset(0-9)andаvalue.(-1tostop)990Enteranoffset(0-9)andаvalue.(-1tostop)1010***Pleaseusevaluesbetween0and9.***Enteranoffset(0-9)andavalue.(-1tostop):-1-1intArray:...[0]0[1]10[2]20[3]30[4]40[5]50[6]60[7]70[8]80[9]90animalArray:...[0]0[1]100[2]200[3]300[4]400[5]500[6]600[7]700[8]800[9]900Анализ: В целях экономии места большая часть выполнения класса Array не показана вэтом листинге.
Класс Animal объявляется в строках 6—23. И хотя структура этого классапредельно упрощена, тем не менее в нем содержится собственный оператор вывода (<<),позволяющийвыводитьнаэкранобъектымассиватипаAnimal.Обратитевнимание,чтовклассеAnimalобъявленконструкторпоумолчанию(конструкторбез параметров, который еще называют стандартный). Без этого объявления нельзя обойтись,поскольку при добавлении объекта в массив используется конструктор по умолчанию данногообъекта.Приэтомвозникаютопределенныетрудности,окоторыхречьпойдетниже.В строке 101 объявляется функция IntFillFunction(), параметром которой являетсяцелочисленныймассив.Обратитевнимание,чтоэтафункциянепринадлежитшаблону,поэтомуможетпринятьтолькомассивцелочисленныхзначений.Аналогичнымобразомвстроке102объявляетсяфункцияAnimalFillFunction(),котораяпринимаетмассивобъектовтипаAnimal.Эти функции выполняются по-разному, поскольку заполнение массива целых чиселотличаетсяотзаполнениямассиваобъектовAnimal.СпециализированныефункцииЕсли разблокировать выражения вывода на экран в конструкторах и деструкторе классаAnimal (см.
листинг 19.5), то обнаружится, что конструктор и деструктор объектов Animalвызываютсязначительночаще,чеможидалось.При добавлении объекта в массив вызывается стандартный конструктор объекта. ОднакоконструкторклассаArrayтакжеиспользуетсядляприсвоениянулевыхзначенийкаждомучленумассива,какпоказановстроках59и60листинга19.2.В выражении someAnimal = (Animal) 0; вызывается стандартный оператор operator= дляклассаAnimal.ЭтоприводитксозданиювременногообъектаAnimalспомощьюконструктора,которыйпринимаетцелоечисло(нуль).Этотвременныйобъектвыступаетправымоперандомвоперацииприсваивания,послечегоудаляетсядеструктором.Такой подход крайне неэффективен, поскольку объект Animal уже инициализировандолжным образом.