С++ для начинающих


Открытый интерфейс каждого из четырех


Открытый интерфейс каждого из четырех производных классов состоит из их открытых членов и унаследованных открытых членов Query. Когда мы пишем:
Query *pq = new NmaeQuery( "Monet" );
то получить доступ к открытому интерфейсу Query можно только через pq. А если пишем:
pq->eval();
то вызывается реализация виртуальной eval() из производного класса, на объект которого указывает pq, в данном случае – из класса NameQuery. Строкой
pq->display();
всегда вызывается невиртуальная функция display() из Query. Однако она выводит разрешающее множество строк объекта того производного класса, на который указывает pq. В этом случае мы не стали полагаться на механизм виртуализации, а вынесли разделяемую операцию и необходимые для нее данные в общий абстрактный базовый класс Query. display() – это пример полиморфного программирования, которое поддерживается не виртуальностью, а исключительно с помощью  наследования. Вот ее реализация (это пока только промежуточное решение, как мы увидим в последнем разделе):
void
Query::
display()
{
   if ( ! _solution->size() ) {
      cout << "\n\tИзвините, "


           << " подходящих строк в тексте не найдено.\n"
           << endl;
   }
   set<short>::const_iterator
       it = _solution->begin(),
       end_it = _solution->end();
   for ( ; it != end_it; ++it ) {
      int line = *it;
      // не будем пользоваться нумерацией строк с 0...
      cout << "(" << line+1 << " ) "
           << (*_text_file)[line] << '\n';
   }
   cout << endl;
}
В этом разделе мы попытались определить иерархию классов Query. Однако вопрос о том, как же построить с ее помощью структуру данных, описывающую запрос пользователя, остался без ответа. Когда мы приступим к реализации, это определение придется пересмотреть и расширить. Но прежде нам предстоит более детально изучить механизм наследования в языке C++.


Упражнение 17.3
Рассмотрите приведенные члены иерархии классов для поддержки библиотеки из упражнения 17.1 (раздел 17.1). Выявите возможные кандидаты на роль виртуальных функций, а также те члены, которые являются общими для всех предметов, выдаваемых библиотекой, и, следовательно, могут быть представлены в базовом классе. (Примечание: LibMember – это абстракция человека, которому разрешено брать из библиотеки различные предметы; Date – класс, представляющий календарную дату.)
class Library {
public:
   bool check_out( LibMember* );   // выдать
   bool check_in ( LibMember* );   // принять назад
   bool is_late( const Date& today );  // просрочил
   double apply_fine();                // наложить штраф
   ostream& print( ostream&=cout );
   Date* due_date() const;             // ожидаемая дата возврата
   Date* date_borrowed() const;        // дата выдачи
   string title() const;               // название
   const LibMember* member() const;    // записавшийся
};
Упражнение 17.4
Идентифицируйте члены базового и производных классов для той иерархии, которую вы выбрали в упражнении 17.2 (раздел 17.1). Задайте виртуальные функции, а также открытые и защищенные члены.
Упражнение 17.5
Какие из следующих объявлений неправильны:
class base { ... };
(a) class Derived : public Derived { ... };
(b) class Derived : Base { ... };
(c) class Derived : private Base { ... };
(d) class Derived : public Base;
(e) class Derived inherits Base { ... };

Содержание раздела