17.2.2. Определение производных классов

17.2.2. Определение производных классов

Каждый производный класс наследует данные и функции-члены своего базового класса, и программировать приходится лишь те аспекты, которые изменяют или расширяют его поведение. К примеру, в классе NameQuery необходимо определить реализацию eval(). Кроме того, нужна поддержка для хранения слова-операнда, представленного объектом класса типа string.

Наконец, для получения ассоциированного вектора позиций должно быть доступно отображение слов на векторы. Поскольку один такой объект разделяется всеми объектами класса NameQuery, мы объявляем его статическим членом. Первая попытка определения NameQuery (рассмотрение конструкторов, деструктора и копирующего оператора присваивания мы снова отложим) выглядит так:

typedef vectorlocation loc;

class NameQuery : public Query {

public:

// ...

// переопределяет виртуальную функцию Query::eval()2

virtual void eval();

// функция чтения

string name() const { return _name; }

static const mapstring,loc* *word_map() { return _word_map; }

protected:

string _name;

static mapstring,loc* *_word_map;

};

Класс NotQuery в дополнение к предоставлению реализации виртуальной функции eval() должен обеспечить поддержку своего единственного операнда. Поскольку им может быть объект любого из производных классов, определим его как указатель на тип Query. Результат запроса NotQuery, напомним, обязан содержать не только строки текста, где нет указанного слова, но также и номера колонок внутри каждой строки. Например, если есть запрос:

! daddy

то операнд запроса NotQuery включает следующий вектор позиций:

daddy ((0,8),(3,3),(5,5))

Вектор позиций, возвращаемый в ответ на исходный запрос, должен включать все номера колонок в строках (1,2,4). Кроме того, он должен включать все номера колонок в строке (0), кроме колонки (8), все номера колонок в строке (3), кроме колонки (3), и все номера колонок в строке (5), кроме колонки (5).

Простейший способ вычислить все это - создать единственный разделяемый всеми объектами вектор позиций, который содержит пары (строка, колонка) для каждого слова в тексте (полную реализацию мы рассмотрим в разделе 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;

};