Открытый интерфейс каждого из четырех
Открытый интерфейс каждого из четырех производных классов состоит из их открытых членов и унаследованных открытых членов 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; |
}
Упражнение 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 { ... };
В этом разделе мы попытались определить иерархию классов Query. Однако вопрос о том, как же построить с ее помощью структуру данных, описывающую запрос пользователя, остался без ответа. Когда мы приступим к реализации, это определение придется пересмотреть и расширить. Но прежде нам предстоит более детально изучить механизм наследования в языке C++.