Читаем Освой самостоятельно С++ за 21 день. полностью

178:    for (int i=0;i

179:       pNode = pNode->itsNext;

180:

181:    return pNode->itsPart;

182: }

183:

184: Part* PartsList::Find(int & position, int PartNumber) const

185: {

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:       return NULL;

196:    else

197:       return pNode->itsPart;

198: }

199:

200: void PartsList::Iterate(void (Part::*func)const) const

201: {

202:    if (!pHead)

203:       return;

204:    PartNode* pNode = pHead;

205:    do

206:       (pNode->itsPart->*func);

207:    while (pNode = pNode->itsNext);

208: }

209:

210: void PartsList::Insert(Part* pPart)

211: {

212:    PartNode * pNode = new PartNode(pPart);

213:    PartNode * pCurrent = pHead;

214:    PartNode * pNext = 0;

215:

216:    int New = pPart->GetPartNumber;

217:    int Next = 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:       // здесь. Иначе присваиваем значение указателя Next

246:       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: class PartsCatalog : private PartsList

259: {

260:    public:

261:       void Insert(Part *);

262:       int Exists(int PartNumber);

263:       Part * Get(int PartNumber);

264:       operator+(const PartsCatalog &);

265:       void ShowAll { Iterate(Part::Display); }

266:    private:

267: };

268:

269: void PartsCatalog::Insert(Part * newPart)

270: {

271:    int partNumber = newPart->GetPartNumber;

272:    int offset;

273:

274:    if (!Find(offset, partNumber))

275:       PartsList::Insert(newPart);

276:    else

277:    {

278:       cout << partNumber << " was the ";

279:       switch (offset)

280:       {

281:          case 0: cout << "first "; break;

282:          case 1: cout << "second "; break;

283:          case 2: cout << "third "; break;

284:          default: cout << offset+1 << "th ";

285:       }

286:       cout << "entry. Rejected!\n";

287:    }

288: }

289:

290: int PartsCatalog::Exists(int PartNumber)

291: {

292:    int offset;

293:    Find(offset,PartNumber);

294:    return offset;

295: }

296:

297: Part * PartsCatalog::Get(int PartNumber)

298: {

299:    int offset;

300:    return (Find(offset, PartNumber));

301:

302: }

303:

304: int main

305: {

306:    PartsCatalog pc;

307:    Part * pPart = 0;

308:    int PartNumber;

309:    int value;

310:    int choice;

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 << "New PartNumber?: ";

321:       cin >> PartNumber;

322:

323:       if (choice == 1)

324:       {

325:          cout << "Model Year?: ";

326:          cin >> value;

327:          pPart = new CarPart(value,PartNumber);

328:       }

329:       else

330:       {

331:          cout << "Engine Number?: ";

332:          cin >> value;

333:          pPart = new AirPlanePart(value,PartNumber);

334:       }

335:       pc.Insert(pPart);

336:    }

337:    pc.ShowAll;

338:    return 0;

339: }


Результат:

(0)Quit (1)Cat (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


Анализ: В строке 82 класс PartsList объявляется другом класса PartNode. В данном случае объявление класса другом происходит в разделе public объявления класса PartNode, но так поступать вовсе не обязательно. Это объявление можно размещать в любом месте объявления класса, что не изменит его суть. В результате объявления класса как друга все закрытые методы и переменные-члены класса PartNode становятся доступными любой функции-члену класса PartsList.

В строке 160 были внесены изменения в вызове функции-члена GetFirst с учетом появившихся новых возможностей. Теперь вместо возвращения pHead->GetPart эта функция может возвращать закрытую переменную-член pHead->itsPart. Аналогичным образом в функции Insert можно написать pNode->itsNext = pHead вместо переменной-члена pHead->SetNext(pHead).

В данном случае внесенные изменения существенно не улучшили код программы, поэтому нет особых причин делать класс PartsList другом PartNode. В данном примере просто хотелось проиллюстрировать, как работает ключевое слово friend.

Объявление классов-друзей следует применять с осторожностью. Класс объявляется как друг какого-либо иного класса в том случае, когда два класса тесно взаимодействуют друг с другом и открытие доступа одного класса к данным и методам другого класса существенно упрощает код программы. Однако зачастую проще организовать взаимодействие между классами с помощью открытых методов доступа.


Примечание:От начинающих программистов C++ часто можно услышать замечание, что объявление классов-друзей противоречит принципу инкапсуляции, лежащему в основе объектно-ориентированного программирования. Это, честно говоря, довольно широко распространенная бессмыслица. Объявление класса-друга просто расширяет интерфейс другого класса, что влияет на инкапсуляцию не больше, чем открытое наследование классов.


Дружественный класс

Объявление одного класса другом какого-либо иного с помощью ключевого слова friend в объявлении второго класса открывает первому классу доступ к членам второго класса. Иными словами, я могу объявить вас своим другом, но вы не можете объявить себя моим другом. Пример:

class PartNode{

   public:

   friend class PartsList: // обьявление класса PartsList другом PartNode

Перейти на страницу:

Похожие книги

Сущность технологии СОМ. Библиотека программиста
Сущность технологии СОМ. Библиотека программиста

В этой книге СОМ исследуется с точки зрения разработчика C++. Написанная ведущим специалистом по модели компонентных объектов СОМ, она раскрывает сущность СОМ, помогая разработчикам правильно понять не только методы модели программирования СОМ, но и ее основу. Понимание мотивов создания СОМ и ее аспектов, касающихся распределенных систем, чрезвычайно важно для тех разработчиков, которые желают пойти дальше простейших приложений СОМ и стать по-настоящему эффективными СОМ-программистами. Показывая, почему СОМ для распределенных систем (Distributed СОМ) работает именно так, а не иначе, Дон Бокс дает вам возможность применять эту модель творчески и эффективно для ежедневных задач программирования.

Дональд Бокс

Программирование, программы, базы данных / Программирование / Книги по IT