// конструкторы обсуждаются в разделе 17.4

virtual void eval();

const Query *rop() const { return _rop; }

const Query *lop() const { return _lop; }

static void max_col( const vector int *pcol )

{ if ( !_max_col ) _max_col = pcol; }

protected:

Query *_lop;

Query *_rop;

static const vectorint *_max_col;

};

<p>17.2.3. Резюме</p>

Открытый интерфейс каждого из четырех производных классов состоит из их открытых членов и унаследованных открытых членов 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;

}

setshort::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 { ... };

<p>17.3. Доступ к членам базового класса</p>
Перейти на страницу:

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