246071-Либерти-Освой-самостоятельно-С-за-21-день (852741), страница 77
Текст из файла (страница 77)
Единствейное исключение состоит в том, что при необходимостизаместитьметодбазовогоклассавклассеPartsListследуетявноуказатьклассиимяфункции.Закрытое наследование позволяет PartsCatalog унаследовать функциональность базовогокласса и создавать интерфейс, косвенно открывающий доступ к его методам, которые нельзявызыватьнапрямую.Рекомендуется:Применяйте открытое наследование, когда производный класс являетсяразновидностью базового. Используйте вложение классов, когда необходимо делегироватьвыполнение задач другому классу, ограничив при этом доступ к его защищенным членам.Применяйте закрытое наследование, если необходимо реализовать один класс в пределахдругогоиобеспечитьдоступкзащищеннымчленамбазовогокласса.Нерекомендуется:Неприменяйтезакрытоенаследование,еслинеобходимоиспользоватьболее одного объекта базового класса.
Для этих целей больше подойдет вложение классов.Например, если для одного объекта PartsCatalog необходимы два объекта PartsList, вы несможетеиспользоватьзакрытоенаследование.Неиспользуйтеоткрытоенаследование,еслинеобходимозакрытьклиентампроизводногоклассапрямойдоступкметодамбазовогокласса.КлассыдрузьяИногда для выполнения задач, поставленных перед программой, необходимо обеспечитьвзаимодействиенесколькихнезависимыхклассов.Например,классыPartNodeиPartsListтесновзаимосвязаны, и было бы удобно, если бы в PartsList можно было напрямую использоватьуказательitsPartклассаPartNode.Конечно, можно было бы объявить itsPart как открытую или хотя бы защищеннуюпеременную-член, но это далеко не лучший путь, противоречащий самой идее использованияклассов.
Поскольку указатель itsPart является специфическим членом класса PartNode, егоследуетоставитьнедоступнымдлявнешнихклассов.Однако, если вы хотите предоставить данные или закрытые методы какому-либо иномуклассу, достаточно объявить этот класс другом. Это расширит интерфейс вашего классавозможностямикласса-друга.После того как в PartsNode класс PartsList будет объявлен другом, переменные- члены иметодыклассаPartsNodeстанутдоступнымидляPartsList.Важно заметить, что дружественность класса не передается на другие классы. Инымисловами,есливымойдруг,аВаня—вашдруг,этововсенезначит,чтоВанятакжеимойдруг.Кроме того, дружба не наследуется.
Опять же, хотя вы мой друг и я хочу рассказать вам своисекреты,этонеозначает,чтояжелаюподелитьсяимисвашимидетьми.Наконец, дружественность классов односторонняя. Объявление одного класса другомкакого-либо иного класса не делает последний другом первого. Вы при желании можетподелиться своими секретами со мной, но это не значит, что я должен рассказать вам своисекреты.В листинге 15.7 представлена версия листинга 15.6, в которой используется объявлениеклассадруга.Так,классPartsListобъявляетсякакдругклассаPartNode.Ещеразнапомним,чтоэтообъявлениенеделаетклассPartNodeдругомклассаPartsList.Листинг15.7.Использованиеклассов-друзей1:#include<iostream.h>2:3:4:5:6://****************КлассPart************7:8://Абстрактныйбазовыйклассвсехдеталей9:classPart10:{11:public:12:Part():itsPartNumber(1){}13:Part(intPartNumber):14:itsPartNumber(PartNumber){}15:virtual~Part(){}16:intGetPartNumber()const17:{returnitsPartNumber;}18:virtualvoidDisplay()const=0;19:private:20:intitsPartNumber;21:};22:23://выполнениечистойвиртуальнойфункциив24://стандартномвидедлявсехпроизводныхклассов25:voidPart::Display()const26:{27:cout<<"\nPartNumber:";28:cout<<itsPartNumber<<endl;29:}30:31://**************КлассCarPart************32:33:classCarPart:publicPart34:{35:public:36:CarPart():itsModelYear(94){}37:CarPart(intyear,intpartNumber);38:virtualvoidDisplay()const39:{40:Part::Display();41:cout<<"ModelYear:";42:cout<<itsModelYear<<endl;43:}44:private:45:intitsModelYear;46:};47:48:CarPart::CarPart(intyear,intpartNumber):49:itsModelYear(year),50:Part(partNumber)51:{}52:53:54://***********КлассAirPlanePart***********55:56:classAirPlanePart:publicPart57:{58:public:59:AirPlanePart():itsEngineNumber(1){};60:AirPlanePart61:(intEngineNumber,intPartNumber);62:virtualvoidDisplay()const63:{64:Part::Display();65:cout<<"EngineNo.:";66:cout<<itsEngineNumber<<endl;67:}68:private:69:intitsEngineNumber;70:};71:72:AirPlanePart::AirPlanePart73:(intEngineNumber,intPartNumber):74:itsEngineNumber(EngineNumber),75:Part(PartNumber)76:{}77:78://****************КлассPartNode************79:classPartNode80:{81:public:82:friendclassPartsList;83:PartNode(Part*);84:~PartNode();85:voidSetNext(PartNode*node)86:{itsNext=node;}87:PartNode*GetNext()const;88:Part*GetPart()const;89:private:90:Part*itsPart;91:PartNode*itsNext;92:};93:94:95:PartNode::PartNode(Part*pPart):96:itsPart(pPart),97:itsNext(0)98:{}99:100:PartNode::~PartNode()101:{102:deleteitsPart;103:itsPart=0;104:deleteitsNext;105:itsNext=0;106:}107:108://ВозвращаетсяNULL,еслинетследующегоузлаPartNode109:PartNode*PartNode::GetNext()const110:{111:returnitsNext;112:}113:114:Part*PartNode::GetPart()const115:{116:if(itsPart)117:returnitsPart;118:else119:returnNULL;//ошибка120:}121:122:123://**************КлассPartList124:classPartsList125:{126:public:127:PartsList();128:~PartsList();129: // Необходимо, чтобы конструктор-копировщик и оператор соответствовали другдругу130:voidIterate(void(Part::*f)()const)const;131:Part*Find(int&position,intPartNumber)const;132:Part*GetFirst()const;133:voidInsert(Part*);134:Part*operator[](int)const;135:intGetCount()const{returnitsCount;}136:staticPartsList&GetGlobalPartsList()137:{138:returnGiobalPartsList;139:}140:private:141:PartNode*pHead;142:intitsCount;143:staticPartsListGiobalPartsList;144:};145:146:PartsListPartsList::GlobalPartsList;147:148://ImplementationsforLists...149:150:PartsList::PartsList();151:pHead(0),152:itsCount(0)153:{}154:155:PartsList::~PartsList()156:{157:deletepHead;158:}159:160:Part*PartsList::GetFirst()const161:{162:if(pHead)163:returnpHead->itsPart;164:else165:returnNULL;//ловушкаошибок166:}167:168:Part*PartsList::operator[](intoffSet)const169:{170:PartNode*pNode=pHead;171:172:if(!pHead)173:returnNULL;//ловушкаошибок174:175:if(offSet>itsCount)176:returnNULL;//ошибка177:178:for(inti=0;i<offSet;i++)179:pNode=pNode->itsNext;180:181:returnpNode->itsPart;182:}183:184:Part*PartsList::Find(int&position,intPartNumber)const185:{186:PartNode*pNode=0;187:for(pNode=pHead,position=0;188:pNode!=NULL;189:pNode=pNode->itsNext,position++)190:{191:if(pNode->itsPart->GetPartNumber()==PartNumber)192:break;193:}194:if(pNode==NULL)195:returnNULL;196:else197:returnpNode->itsPart;198:}199:200:voidPartsList::Iterate(void(Part::*func)()const)const201:{202:if(!pHead)203:return;204:PartNode*pNode=pHead;205:do206:(pNode->itsPart->*func)();207:while(pNode=pNode->itsNext);208:}209:210:voidPartsList::Insert(Part*pPart)211:{212:PartNode*pNode=newPartNode(pPart);213:PartNode*pCurrent=pHead;214:PartNode*pNext=0;215:216:intNew=pPart->GetPartNumber();217:intNext=0;218:itsCount++;219:220:if(!pHead)221:{222:pHead=pNode;223:return;224:}225:226://еслиэтозначениеменьшеголовногоузла,227://тотекущийузелстановитсяголовным228:if(pHead->itsPart->GetPartNumber()>New)229:{230:pNode->itsNext=pHead;231:pHead=pNode;232:return;233:}234:235:for(;;)236:{237://еслинетследующего,вставляетсятекущий238:if(!pCurrent->itsNext)239:{240:pCurrent->itsNext=pNode;241:return;242:}243:244://еслитекущийбольшепредыдущего,номеньшеследующего,товставляем245://здесь.ИначеприсваиваемзначениеуказателяNext246:pNext=pCurrent->itsNext;247:Next=pNext->itsPart->GetPartNumber();248:if(Next>New)249:{250:pCurrent->itsNext=pNode;251:pNode->itsNext=pNext;252:return;253:}254:pCurrent=pNext;255:}256:}257:258:classPartsCatalog:privatePartsList259:{260:public:261:voidInsert(Part*);262:intExists(intPartNumber);263:Part*Get(intPartNumber);264:operator+(constPartsCatalog&);265:voidShowAll(){Iterate(Part::Display);}266:private:267:};268:269:voidPartsCatalog::Insert(Part*newPart)270:{271:intpartNumber=newPart->GetPartNumber();272:intoffset;273:274:if(!Find(offset,partNumber))275:PartsList::Insert(newPart);276:else277:{278:cout<<partNumber<<"wasthe";279:switch(offset)280:{281:case0:cout<<"first";break;282:case1:cout<<"second";break;283:case2:cout<<"third";break;284:default:cout<<offset+1<<"th";285:}286:cout<<"entry.Rejected!\n";287:}288:}289:290:intPartsCatalog::Exists(intPartNumber)291:{292:intoffset;293:Find(offset,PartNumber);294:returnoffset;295:}296:297:Part*PartsCatalog::Get(intPartNumber)298:{299:intoffset;300:return(Find(offset,PartNumber));301:302:}303:304:intmain()305:{306:PartsCatalogpc;307:Part*pPart=0;308:intPartNumber;309:intvalue;310:intchoice;311:312:while(1)313:{314:cout<<"(0)Quit(1)Car(2)Plane:";315:cin>>choice;316:317:if(!choice)318:break;319:320:cout<<"NewPartNumber?:";321:cin>>PartNumber;322:323:if(choice==1)324:{325:cout<<"ModelYear?:";326:cin>>value;327:pPart=newCarPart(value,PartNumber);328:}329:else330:{331:cout<<"EngineNumber?:";332:cin>>value;333:pPart=newAirPlanePart(value,PartNumber);334:}335:pc.Insert(pPart);336:}337:pc.ShowAll();338:return0;339:}Результат:(0)Quit(1)Cat(2}Plane:1NewPartNumber?:1234ModelYear?:94(0)Quit(1)Car(2)Plane:1NewPartNumber?:4434ModelYear?:93(0)Quit(1)Car(2)Plane:1NewPartNumber?:1234ModelYear?:941234wasthefirstentry.Rejected!(0)Quit(1)Car(2)Plane:1NewPartNumber?:2345ModelYear?:93(0)Quit(1)Car(2)Plane:0PartNumber:1234ModelYear:94PartNumber:2345ModelYear:93PartNumber:4434ModelYear:93Анализ:Встроке82классPartsListобъявляетсядругомклассаPartNode.Вданномслучаеобъявление класса другом происходит в разделе public объявления класса PartNode, но такпоступать вовсе не обязательно.