Язык программирования C++. Вводный курс



Объявления друзей в шаблонах Queue и QueueItem - часть 3


Распечатка элементов Queue производится оператором вывода operator<<()

класса QueueItem:

os << *p;

Этот оператор также должен быть реализован в виде шаблона функции; тогда можно быть уверенным, что в нужный момент будет конкретизирован подходящий экземпляр:

template <class Type>

ostream& operator<<( ostream &os, const QueueItem<Type> &qi )

{

   os << qi.item;

   return os;

}

Поскольку здесь имеется обращение к закрытому члену item класса QueueItem, оператор следует объявить другом шаблона QueueItem. Это делается следующим образом:

template <class Type>

class QueueItem {

   friend class Queue<Type>;

   friend ostream&

      operator<<( ostream &, const QueueItem<Type> & );

   // ...

};

Оператор вывода класса QueueItem

полагается на то, что item

умеет распечатывать себя:

os << qi.item;

Это порождает тонкую зависимость типов при конкретизации Queue. Любой определенный пользователем и связанный с Queue

класс, содержимое которого нужно распечатывать, должен предоставлять оператор вывода. В языке нет механизма, с помощью которого можно было бы задать такую зависимость в определении самого шаблона Queue. Но если оператор вывода не определен для типа, с которым конкретизируется данный шаблон, и делается попытка вывести содержимое конкретизированного экземпляра, то в том месте, где используется отсутствующий оператор вывода, компилятор выдает сообщение об ошибке. Шаблон Queue

можно конкретизировать типом, не имеющим оператора вывода, – при условии, что не будет попытки распечатать содержимое очереди.

Следующая программа демонстрирует конкретизацию и использование функций-друзей шаблонов классов Queue и QueueItem:

#include <iostream>

#include "Queue.h"

int main() {

   Queue<int> qi;

   // конкретизируются оба экземпляра

   //   ostream& operator<<(ostream &os, const Queue<int> &)

   //   ostream& operator<<(ostream &os, const QueueItem<int> &)

   cout << qi << endl;

   int ival;

   for ( ival = 0; ival < 10; ++ival )

      qi.add( ival );

   cout << qi << endl;

   int err_cnt = 0;

   for ( ival = 0; ival < 10; ++ival ) {

      int qval = qi.remove();

      if ( ival != qval ) err_cnt++;

   }

   cout << qi << endl;

   if ( !err_cnt )

      cout << "!! queue executed ok\n";

   else cout << "?? queue errors: " << err_cnt << endl;

   return 0;

}

После компиляции и запуска программа выдает результат:

< >

< 0 1 2 3 4 5 6 7 8 9 >

< >

!! queue executed ok

Упражнение 16.6

Пользуясь шаблоном класса Screen, определенным в упражнении 16.5, реализуйте операторы ввода и вывода (см. упражнение 15.6 из раздела 15.2) в виде шаблонов. Объясните, почему вы выбрали тот, а не иной способ объявления друзей класса Screen, добавленных в его шаблон.




Содержание  Назад  Вперед