Главная страница Случайная страница КАТЕГОРИИ: АвтомобилиАстрономияБиологияГеографияДом и садДругие языкиДругоеИнформатикаИсторияКультураЛитератураЛогикаМатематикаМедицинаМеталлургияМеханикаОбразованиеОхрана трудаПедагогикаПолитикаПравоПсихологияРелигияРиторикаСоциологияСпортСтроительствоТехнологияТуризмФизикаФилософияФинансыХимияЧерчениеЭкологияЭкономикаЭлектроника |
Листинг 15.5. Делегирование ответственности классу PartsList, включенному в класс PartsCatalog
1: #include < iostream.h> 2: 3: // **************** Класс Part ************ 4: 5: // Абстрактный базовый класс всех деталей 6: class Part 7: { 8: public: 9: Part(): itsPartNumber(1) { } 10: Part(int PartNumber): 11: itsPartNumber(PartNumber){ } 12: virtual ~Part(){ } 13: int GetPartNumber() const 14: { return itsPartNumber; } 15: virtual void Display() const =0; 16: private: 17: int itsPartNumber; 18: }; 19: 20: // выполнение чистой виртуальной функции в 21: // стандартном виде для всех производных классов 22: void Part:: Display() const 23: { 24: cout < < " \nPart Number: " < < itsPartNumber < < endl; 25: } 26: 27: // ************ Автомобильные детали ********** 28: 29: class CarPart: public Part 30: { 31: public: 32: CarPart(): itsModelYear(94){ } 33: CarPart(int year, int partNumber); 34: virtual void Display() const 35: { 36: Part:: Display(); 37: cout < < " Model Year: "; 38: cout < < itsModelYear < < endl; 39: } 40: private: 41: int itsModelYear; 42: }; 43: 44: CarPart:: CarPart(int year, int partNumber): 45: itsModelYear(year), 46: Part(partNumber) 47: { } 48: 49: 50: // ************* Авиационные детали ************ 51: 52: class AirPlanePart: public Part 53: { 54: public: 55: AirPlanePart(): itsEngineNumber(1){ } 56: AirPlanePart 57: (int EngineNumber, int PartNumber) 58: virtual void Dlsplay() const 59: { 60: Part:: Display(); 61: cout < < " Engine No.: "; 62: cout < < itsEngineNumber < < endl; 63: } 64: private: 65: int itsEngineNumber; 66: }; 67: 68: AirPlanePart:: AirPlanePart 69: (int EngineNumber, int PartNumber): 70: itsEngineNumber(EngineNumber), 71: Part(PartNumber) 72: { } 73: 74: // *************** Узлы списка деталей ********** 75: class PartNode 76: { 77: public: 78: PartNode (Part*); 79: ~PartNode(); 80: void SetNext(PartNode * node) 81: { itsNext = node; } 82: PartNode * GetNext() const; 83: Part * GetPart() const; 84: private: 85: Part *itsPart; 86: PartNode * itsNext; 87: }; 88: // Выполнение PartNode... 89: 90: PartNode:: PartNode(Part* pPart): 91: itsPart(pPart), 92: itsNext(0) 93: { } 94: 95: PartNode:: ~PartNode() 96: { 97: delete itsPart; 98: itsPart = 0; 99: delete itsNext; 100: itsNext = 0; 101: } 102: 103: // Возвращается NULL, если нет следующего узла PartNode 104: PartNode * PartNode:: GetNext() const 105: { 106: return itsNext; 107: } 108: 109: Part * PartNode:: GetPart() const 110: { 111: if (itsPart) 112: return itsPart; 113: else 114: return NULL; //ошибка 115: } 116: 117: 118: 119: // **************** Список деталей *********** 120: class PartsList 121: { 122: public: 123: PartsList(); 124: ~PartsList(); 125: // необходимо, чтобы конструктор-копировщик и оператор соответствовали друг другу! 126: void Iterate(void (Part:: *f)()const) const; 127: Part* Find(int & position, int PartNumber) const; 128: Part* GetFirst() const; 129: void Insert(Part *); 130: Part* operator[](int) const; 131: int GetCount() const { return itsCount; } 132: static PartsList& GetGlobalPartsList() 133: { 134: return GiobalPartsList; 135: } 136: private: 137: PartNode * pHead; 138: int itsCount; 139: static PartsList GiobalPartsList; 140: }; 141: 142: PartsList PartsList:: GlobalPartsList; 143: 144: 145: PartsList:: PartsList(): 146: pHead(0), 147: itsCount(0) 148: { } 149: 150: PartsList:: ~PartsList() 151: { 152: delete pHead; 153: } 154: 155: Part* PartsList:: GetFirst() const 156: { 157: if (pHead) 158: return pHead-> GetPart(); 159: else 160: return NULL; // ловушка ошибок 161: } 162: 163: Part * PartsList:: operator[](int offSet) const 164: { 165: PartNode* pNode = pHead; 166: 167: if (! pHead) 168: return NULL; // ловушка ошибок 169: 170: if (offSet > itsCount) 171: return NULL; // ошибка 172: 173: for (int i=0; i< offSet; i++) 174: pNode = pNode-> GetNext(); 175: 176: return pNode-> GetPart(); 177: } 178: 179: Part* PartsList:: Find( 180: int & position, 181: int PartNumber) const 182: { 183: PartNode * pNode = 0; 184: for (pNode = pHead, position = 0; 185: pNode! =NULL; 186: pNode = pNode-> GetNext(), position++) 187: { 188: if (pNode-> GetPart()-> GetPartNumber()== PartNumber) 189: break; 190: } 191: if (pNode == NULL) 192: return NULL; 193: else 194: return pNode-> GetPart(); 195: } 196: 197: void PartsList:: Iterate(void (Part:: *func)()const) const 198: { 199: if (! pHead) 200: return; 201: PartNode* pNode = pHead; 202: do 203: (pNode-> GetPart()-> *func)(); 204: while (pNode = pNode-> GetNext()); 205: } 206: 207: void PartsList:: Insert(Part* pPart) 208: { 209: PartNode * pNode = new PartNode(pPart); 210: PartNode * pCurrent - pHead; 211: PartNode * pNext = 0; 212: 213: int New = pPart-> GetPartNumber(); 214: int Next = 0; 215: itsCount++; 216: 217: if (! pHead) 218: { 219: pHead = pNode; 220: return; 221: } 222: 223: // если это значение меньше головного узла, 224: // то текущий узел становится головным 225: if (pHead-> GetPart()-> GetPartNumber()-> New) 226: { 227: pNode-> SetNext(pHead); 228: pHead = pNode; 229: return; 230: } 231: 232: for (;;) 233: { 234: // если нет следующего, вставляется текущий 235: if (! pCurrent-> GetNext()) 236: { 237: pCurrent-> SetNext(pNode); 238: return; 239: } 240: 241: // если текущий больше предыдущего, но меньше следующего, то вставляем 242: // здесь. Иначе присваиваем значение указателя Next 243: pNext = pCurrent-> GetNext(); 244: Next = pNext-> GetPart()-> GetPartNumber(); 245: if (Next > New) 246: { 247: pCurrent-> SetNext(pNode); 248: pNode-> SetNext(pNext); 249: return; 250: } 251: pCurrent = pNext; 252: } 253: } 254: 255: 256: 257: class PartsCatalog 258: { 259: public: 260: void Insert(Part *); 261: int Exists(int PartNumber); 262: Part * Get(int PartNumber); 263: operator+(const PartsCatalog &); 264: void ShowAll() { thePartsList.Iterate(Part:: Display); } 265: private: 266: PartsList thePartsList; 267: }; 268: 269: void PartsCatalog:: Insert(Part * newPart) 270: { 271: int partNumber = newPart-> GetPartNumber(); 272: int offset; 273: 274: if (! thePartsList, Find(offset, partNumber)) 275: 276: thePartsList.Insert(newPart); 277: else 278: { 279: cout < < partNumber < < " был "; 280: switch (offset) 281: { 282: case 0: cout < < " first "; break; 283: case 1: cout < < " second "; break; 284: case 2: cout < < " third "; break; 285: default; cout < < offset+1 < < " th "; 286: } 287: cout < < " entry. Rejected! \n"; 288: } 289: } 290: 291: int PartsCatalog:: Exists(int PartNumber) 292: { 293: int offset; 294: thePartsList.Find(offset, PartNumber); 295: return offset; 296: } 297: 298: Part * PartsCatalog:: Get(int PartNumber) 299: { 300: int offset; 301: Part * thePart = thePartsList.Find(offset, PartNumber); 302: return thePart; 303: } 304: 305: 306: int main() 307: { 308: PartsCatalog pc; 309: Part * pPart = 0; 310: int PartNumber; 311: int value; 312: int choice; 313: 314: while (1) 315: { 316: cout < < " (0)Quit (1)Car (2)Plane: "; 317: cin > > choice; 318: 319: if (! choice) 320: break; 321: 322: cout < < " New PartNumber?: "; 323: cin > > PartNumber; 324: 325: if (choice == 1) 326: { 327: cout < < " Model Year?: "; 328: cin > > value; 329: pPart = new CarPart(value, PartNumber); 330: } 331: else 332: { 333: cout < < " Engine Number?: "; 334: cin > > value; 335: pPart = new AirPlanePart(value, PartNumber); 335: } 337: pc.Insart(pPart); 338: } 339: pc.ShowAli(); 340: return 0; 341: }
Результат: (0)Qult (1)Car (2)Plane: 1 New PartNumber?: 1234 Model Year?: 94 (0)Quit (1)Car (2)Plane: 1 New PartNumber?: 4434 Model Year?: 93 (0)Quit (1)Car (2)Plane: 1 New PartNumber?: 1234 Model Year?: 94 1234 was the first entry. Rejected! (0)Quit (1)Car (2)Plane: 1 New PartNumber?: 2345 Model Year?: 93 (0)Quit (1)Car (2)Plane: 0 Part Number: 1234 Model Year: 94 Part Number: 2345 Model Year: 93 Part Number: 4434 Model Year: 93
Примечание: Некоторые компиляторы не смогут откомпилировать строку 264, хотя она вполне соответствует стандартам C++. Если ваш компилятор возразит против записи этой строки, замените ее строкой 264: void ShowAll() { thePartsList.Iterate(& Part:: Display): } (Обратите внимание на добавление амперсанта (знак &) перед Part: Display.) Если это сработает, свяжитесь с фирмой, поставившей вам этот компилятор, и поинтересуйтесь, где они его " откопали".
Анализ: В листинге 15.5 используются классы Part, PartNode и PartsList, с которыми вы уже познакомились при подведении итогов второй недели. Новый класс PartsCatalog объявляется в строках 257—267. Он использует PartsList как свою переменную-член, которой делегирует управление списком. Другими словами, класс PartsCatalog выполняется средствами классе PartsList. Обратите внимание, что клиенты класса PartsCatalog не имеет прямого доступа к классу PartsList. Интерфейс класса PartsList реализуется методами класса PartsCatalog, что существенно изменяет его поведение. Например, метод PartsCatalog:: Insert() не позволяет дублировать данные, вводимые в PartsList. Определение выполнения функции PartsCatalog:: Insert() начинается в строке 269. У объекта Part, передаваемого как параметр, запрашивается значение его переменной- члена itsPartNumber. Это значение передается методу Find() класса PartsList, и объект добавляется в список, если только в списке не найден другой объект с таким же номером. В противном случае возвращается сообщение об ошибке. Обратите внимание, что в методе Insert() класса PartCatolog используется переменная-член этого класса thePartList, являющаяся объектом класса PartList. Процедура поддержания связного списка и добавления объектов в него, а также поиска и возвращения данных из списка полностью реализуется вложенным классом PartsList, объект которого является переменной-членом класса PartsCatalog. Вместо того чтобы повторять все процедуры обработки записей списка в классе PartsCatalog, методами этого класса просто создается удобный интерфейс для уже существующего класса PartsList. Именно в этом и состоит суть модульности программирования на C++. Удачно созданный однажды модуль, такой как PartsLists, можно многократно использовать в других программах, например с классом PartsCatalog. При этом разработчиков нового класса PartsCatalog могут совершенно не интересовать детали выполнения модуля PartsList. Интерфейс класса PartsList (в данном случае под интерфейсом понимается его объявление) предоставляет всю информацию, необходимую разработчику нового класса PartsCatalog.
|