246071-Либерти-Освой-самостоятельно-С-за-21-день (852741), страница 76
Текст из файла (страница 76)
Вместо того чтобы повторять все процедуры обработки записейсписка в классе PartsCatalog, методами этого класса просто создается удобный интерфейс дляужесуществующегоклассаPartsList.Именно в этом и состоит суть модульности программирования на C++. Удачно созданныйоднажды модуль, такой как PartsLists, можно многократно использовать в других программах,например с классом PartsCatalog. При этом разработчиков нового класса PartsCatalog могутсовершеннонеинтересоватьдеталивыполнениямодуляPartsList.ИнтерфейсклассаPartsList(вданномслучаеподинтерфейсомпонимаетсяегообъявление)предоставляетвсюинформацию,необходимуюразработчикуновогоклассаPartsCatalog.ЗакрытоенаследованиеЕсли бы для PartsCatalog был необходим доступ к защищенным членам PartsList (в данномпримере таковых нет) или в PartsCatalog использовались замещенные методы PartsList, то егоможнобылобыпростоунаследоватьотPartsList.Однако, поскольку PartsCatalog не является объектом PartsList и нежелательнопредоставлять весь набор функциональных возможностей PartsList клиентам PartsCatalof,следуетприменитьзакрытоенаследование.Первое, что необходимо знать: при закрытом наследовании все переменные и функциичленыбазовогоклассатрактуютсятак,какеслибыонибылиобъявленызакрытыми,независимоот установок доступа в базовом классе.
Таким образом, для любой функции, не являющейсяфункцией-членом PartsCatalog, недоступны функции, унаследованные из PartsList. Это оченьважно:закрытоенаследованиенепередаетвпроизводныйклассинтерфейсбазовогокласса.Класс PartsList невидим для клиентов класса PartsCatalog. Поэтому последним недоступенинтерфейс класса PartsList и они не могут вызывать его методы.
Однако пользователям будутдоступнывсеметодыклассаPartsCatalog,имеющиедоступковсемчленамклассаPartsList,таккак класс PartsCatalog является производным от PartList. Важно также то, что объектыPartsCatalog не являются объектами PartsList, как было бы при использовании открытогонаследования. Класс PartsCatalog выполняется методами класса PartsList, как в случае свложением.Применениезакрытогонаследованиянеменееудобно.Использование закрытого наследования показано в листинге 15.6.
Класс PartsCatalogпроизводитсякакprivateотклассаPartsList.Листинг15.6.Закрытоенаследование1://Листинг15.6.Закрытоенаследование2:#include<iostream.h>3:4://****************КлассPart************5:6://Абстрактныйбазовыйклассвсехдеталей7:classPart8:{9:public:10:Part():itsPartNumber(1){}11:Part(intPartNumber):12:itsPartNumber(PartNumber){}13:virtual~Part(){}14:intGetPartNumber()const15:{returnitsPartNumber;}16:virtualvoidDisplay()const=0;17:private:18:intitsPartNumber;19:};20:21://выполнениечистойвиртуальнойфункциив22://стандартномвидедлявсехпроизводныхклассов23:voidPart::Display()const24:{25:cout<<"\nPartNumber:"<<itsPartNumber<<endl;26:}27:28://****************CarPart************29:30:classCarPart:publicPart31:{32:public:33:CarPart():itsModelYear(94){}34:CarPart(intyear,intpartNumber);35:virtualvoidDisplay()const36:{37:Part::Display();38:cout<<"ModelYear:";39:cout<<itsModelYear<<endl;40:}41:private:42:intitsModelYear;43:};44:45:CarPart::CarPart(intyear,intpartNumber):46:itsModelYear(year),47:Part(partNumber)48:{}49:50:51://***********КлассAirPlanePart**********52:53:classAirPlanePart:publicPart54:{55:public:56:AirPlanePart():itsEngineNumber(1){}57:AirPlanePart58:(intEngineNumber,intPartNumber);59:virtualvoidDisplay()const60:{61:Part::Display();62:cout<<"EngineNo.:";63:cout<<itsEngineNumber<<endl;64:}65:private:66:intitsEngineNumDer;67:};68:69:AirPlanePart::AirPlanePart70:(intEngineNumber,intPartNumber):71:itsEngineNumber(EngineNumber),72:Part(PartNumber)73:{}74:75://************КлассPartNode************76:classPartNode77:{78:public:79:PartNode(Part>>);80:~PartNode();81:voidSetNext(PartNode*node)82:{itsNext=node;}83:PartNode*GetNext()const;84:Part*GetPart()const;85:private:86:Part*itsPart;87:PartNode*itsNext;88:};89://ВыполнениеPartNode...90:91:PartNode::PartNode(Part*pPart):92:itsPart(pPart),93:itsNext(0)94:{}95:96:PartNode::~PartNode()97:{98:deleteitsPart;99:itsPart=0;100:deleteitsNext;101:itsNext=0;102:}103:104://ВозвращаетNULLNULL,еслинетследующегоузлаPartNode105:PartNode*PartNode::GetNext()const106:{107:returnitsNext;108:}109:110:Part*PartNode::GetPart()const111:{112:if(itsPart)113:returnitsPart;114:else115:returnNULL;//ошибка116:}117:118:119:120://************КлассPartList************121:classPartsList122:{123:public:124:PartsList();125:~PartsList();126: // Необходимо, чтобы конструктор-копировщик и оператор соответствовали другдругу!127:voidIterate(void(Part::*f)()const)const;128:Part*Find(int&position,intPartNumber)const;129:Part*GetFirst()const;130:voidInsert(Part*);131:Part*operator[](int)const;132:intGetCount()const{returnitsCount;}133:staticPartsList&GetGlobalPartsList()134:{135:returnGiobalPartsList;136:}137:private:138:PartNode*pHead;139:intitsCount;140:staticPartsListGiobalPartsList;141:};142:143:PartsListPartsList::GlobalPartsList;144:145:146:PartsList::PartsList():147:pHead(0),148:itsCount(0)149:{}150:151:PartsList::~PartsList()152:{153:deletepHead;154:}155:156:Part*PartsList::GetFirst()const157:{158:if(pHead)159:returnpHead->GetPart();160:else161:returnNULL;//ловушкаошибок162:}163:164:Part*PartsList::operator[](intoffSet)const165:{166:PartNode*pNode=pHead;167:168:if(!pHead)169:returnNULL;//ловушкаошибок170:171:if(offSet>itsCount)172:returnNULL;//ошибка173:174:for(inti=0;i<offSet;i++)175:pNode=pNode->GetNext();176:177:returnpNode->GetPart();178:}179:180:Part*PartsList::Find(181:int&position,182:intPartNumber)const183:{184:PartNode*pNode=0;185:for(pNode=pHead,position=0;186:pNode!=NULL;187:pNode=pNode->GetNext(),position++)188:{189:if(pNode->GetPart()->GetPartNumber()==PartNumber)190:break;191:}192:if(pNode==NULL)193:returnNULL;194:else195:returnpNode->GetPart();196:}197:198:voidPartsList::Iterate(void(Part::*func)()const)const199:{200:if(!pHead)201:return;202:PartNode*pNode=pHead;203:do204:(pNode->GetPart()->*func)();205:while(pNode=pNode->GetNext());206:}207:208:voidPartsList::Insert(Part*pPart)209:{210:PartNode*pNode=newPartNode(pPart);211:PartNode*pCurrent=pHead;212:PartNode*pNext=0;213:214:intNew=pPart->GetPartNumber();215:intNext=0;216:itsCount++;217:218:if(!pHead)219:{220:pHead=pNode;221:return;222:}223:224://еслиэтозначениеменьшеголовногоузла,225://тотекущийузелстановитсяголовным226:if(pHead->GetPart()->GetPartNumber()->New)227:{228:pNode->SetNext(pHead);229:pHead=pNode;230:return;231:}232:233:for(;;)234:{235://еcлинетследующего,вставляетсятекущий236:if(!pCurrent->GetNext())237:{238:pCurrent->SetNext(pNode);239:return;240:}241:242://еслитекущийбольшепредыдущего,номеньшеследующего,товставляем243://здесь,ИначеприсваиваемзначениеуказателяNext244:pNext=pCurrent->GetNext();245:Next=pNext->GetPart()->GetPartNumber();246:if(Next>New)247:{248:pCurrent->SetNext(pNode);249:pNode->SetNext(pNext);250:return;251:}252:pCurrent=pNext;253:}254:}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)Car(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Анализ:Влистинге15.6былизмененинтерфейсклассаPartsCatalogипереписанафункцияmain().Интерфейсыдругихклассовосталисьтакимиже,какивлистинге15.5.В строке 258 листинга 15.6 класс PartsCatalog производится как private от класса PartsList.Интерфейс класса PartsCatalog остался таким же, как и в листинге 15.5, хотя, конечно же,необходимостьвобъектахклассаPartsListкакпеременных-членахотпала.Функция-член ShowAll() класса PartsCatalog вызывает функцию Iterate() из PartsList,параметромкоторойзадаетсяуказательнафункцию-членклассаPart.Такимобразом,функцияShowAll() выполняет роль открытого интерфейса, позволяя пользователям получатьинформацию, не обращаясь напрямую к закрытой функции Iterate(), прямой доступ к которойзакрытдляклиентовклассаPartsCatalog.ФункцияInsert()тожеизменилась.Обратитевнимание,встроке274функцияFind()теперьвызываетсянепосредственно,посколькуонанаследуетсяизбазовогокласса.ЧтобыпривызовефункцииInsert()невозниклозацикливанияфункциинасамоесебя,встроке275делаетсяявныйвызовфункциисуказаниемименикласса.Такимобразом,еслиметодамклассаPartsCatalogнеобходимовызватьметодыPartsList,онимогут делать это напрямую.