Выбрать главу

Простейший способ вычислить все это - создать единственный разделяемый всеми объектами вектор позиций, который содержит пары (строка, колонка) для каждого слова в тексте (полную реализацию мы рассмотрим в разделе 17.5, когда будем обсуждать функцию eval() класса NotQuery). Так или иначе, этот член мы объявим статическим для NotQuery.

Вот определение класса NotQuery (и снова рассмотрение конструкторов, деструктора и копирующего оператора присваивания отложено):

class NotQuery : public Query {

public:

// ...

// альтернативный синтаксис: явно употреблено ключевое слово virtual

// переопределение Query::eval()

virtual void eval();

// функция доступа для чтения

const Query *op() const { return _op; }

static const vector location * all_locs() {

return _all_locs; }

protected:

Query *_op;

static const vector location *_all_locs;

};

Классы AndQuery и OrQuery представляют бинарные операции, у которых есть левый и правый операнды. Оба операнда могут быть объектами любого из производных классов, поэтому мы определим соответствующие члены как указатели на тип Query. Кроме того, в каждом классе нужно переопределить виртуальную функцию eval(). Вот начальное определение OrQuery:

class OrQuery : public Query {

public:

// ...

virtual void eval();

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

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

protected:

Query *_lop;

Query *_rop;

};

Любой объект AndQuery должен иметь доступ к числу слов в каждой строке. В противном случае при обработке запроса AndQuery мы не сможем найти соседние слова, расположенные в двух смежных строках. Например, если есть запрос:

tell && her && magical

то нужная последовательность находится в третьей и четвертой строках:

like a fiery bird in flight. A beautiful fiery bird, he tells her,

magical but untamed. "Daddy, shush, there is no such thing, "

Векторы позиций, ассоциированные с каждым из трех слов, следующие:

her ((0,7),(1,5),(2,12),(4,11))

magical ((3,0))

tell ((2,11),(4,1),(4,10))

Если функция eval() класса AndQuery "не знает ", сколько слов содержится в строке (2), то она не сможет определить, что слова magical и her соседствуют. Мы создадим единственный экземпляр вектора, разделяемый всеми объектами класса, и объявим его статическим членом. (Реализацию eval() мы детально рассмотрим в разделе 17.5.) Итак, определим AndQuery:

class AndQuery : public Query {

public:

// конструкторы обсуждаются в разделе 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;

};

17.2.3. Резюме

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