Студопедия

Главная страница Случайная страница

Разделы сайта

АвтомобилиАстрономияБиологияГеографияДом и садДругие языкиДругоеИнформатикаИсторияКультураЛитератураЛогикаМатематикаМедицинаМеталлургияМеханикаОбразованиеОхрана трудаПедагогикаПолитикаПравоПсихологияРелигияРиторикаСоциологияСпортСтроительствоТехнологияТуризмФизикаФилософияФинансыХимияЧерчениеЭкологияЭкономикаЭлектроника






Листинг 15.7. Использование классов-друзей






1: #include < iostream.h>

2:

3:

4:

5:

6: // **************** Класс Part ************

7:

8: // Абстрактный базовый класс всех деталей

9: class Part

10: {

11: public:

12: Part(): itsPartNumber(1) { }

13: Part(int PartNumber):

14: itsPartNumber(PartNumber){ }

15: virtual ~Part(){ }

16: int GetPartNumber() const

17: { return itsPartNumber; }

18: virtual void Display() const =0;

19: private:

20: int itsPartNumber;

21: };

22:

23: // выполнение чистой виртуальной функции в

24: // стандартном виде для всех производных классов

25: void Part:: Display() const

26: {

27: cout < < " \nPart Number: ";

28: cout < < itsPartNumber < < endl;

29: }

30:

31: // ************** Класс Car Part ************

32:

33: class CarPart: public Part

34: {

35: public:

36: CarPart(): itsModelYear(94){ }

37: CarPart(int year, int partNumber);

38: virtual void Display() const

39: {

40: Part:: Display();

41: cout < < " Model Year: ";

42: cout < < itsModelYear < < endl;

43: }

44: private:

45: int itsModelYear;

46: };

47:

48: CarPart:: CarPart(int year, int partNumber):

49: itsModelYear(year),

50: Part(partNumber)

51: { }

52:

53:

54: // *********** Класс AirPlane Part ***********

55:

56: class AirPlanePart: public Part

57: {

58: public:

59: AirPlanePart(): itsEngineNumber(1){ };

60: AirPlanePart

61: (int EngineNumber, int PartNumber);

62: virtual void Display() const

63: {

64: Part:: Display();

65: cout < < " Engine No.: ";

66: cout < < itsEngineNumber < < endl;

67: }

68: private:

69: int itsEngineNumber;

70: };

71:

72: AirPlanePart:: AirPlanePart

73: (int EngineNumber, int PartNumber):

74: itsEngineNumber(EngineNumber),

75: Part(PartNumber)

76: { }

77:

78: // **************** Класс Part Node ************

79: class PartNode

80: {

81: public:

82: friend class PartsList;

83: PartNode (Part*);

84: ~PartNode();

85: void SetNext(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: delete itsPart;

103: itsPart = 0;

104: delete itsNext;

105: itsNext = 0;

106: }

107:

108: // Возвращается NULL, если нет следующего узла PartNode

109: PartNode * PartNode:: GetNext() const

110: {

111: return itsNext;

112: }

113:

114: Part * PartNode:: GetPart() const

115: {

116: if (itsPart)

117: return itsPart;

118: else

119: return NULL; //ошибка

120: }

121:

122:

123: // ************** Класс Part List

124: class PartsList

125: {

126: public:

127: PartsList();

128: ~PartsList();

129: // Необходимо, чтобы конструктор-копировщик и оператор соответствовали друг другу

130: void Iterate(void (Part:: *f)()const) const;

131: Part* Find(int & position, int PartNumber) const;

132: Part* GetFirst() const;

133: void Insert(Part *);

134: Part* operator[](int) const;

135: int GetCount() const { return itsCount; }

136: static PartsList& GetGlobalPartsList()

137: {

138: return GiobalPartsList;

139: }

140: private:

141: PartNode * pHead;

142: int itsCount;

143: static PartsList GiobalPartsList;

144: };

145:

146: PartsList PartsList:: GlobalPartsList;

147:

148: // Implementations for Lists...

149:

150: PartsList:: PartsList();

151: pHead(0),

152: itsCount(0)

153: { }

154:

155: PartsList:: ~PartsList()

156: {

157: delete pHead;

158: }

159:

160: Part* PartsList:: GetFirst() const

161: {

162: if (pHead)

163: return pHead-> itsPart;

164: else

165: return NULL; // ловушка ошибок

166: }

167:

168: Part * PartsList:: operator[](int offSet) const

169: {

170: PartNode* pNode = pHead;

171:

172: if (! pHead)

173: return NULL; // ловушка ошибок

174:

175: if (offSet > itsCount)

176: return NULL; // ошибка

177:

178: for (int i=0; i< offSet; 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++ часто можно услышать замечание, что объявление классов-друзей противоречит принципу инкапсуляции, лежащему в основе объектно-ориентированного программирования. Это, честно говоря, довольно широко распространенная бессмыслица. Объявление класса-друга просто расширяет интерфейс другого класса, что влияет на инкапсуляцию не больше, чем открытое наследование классов.

 






© 2023 :: MyLektsii.ru :: Мои Лекции
Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав.
Копирование текстов разрешено только с указанием индексируемой ссылки на источник.