|
Программирование >> Инициализация объектов класса, структура
her && hair слова встречаются в четырех разных строках. Определенная нами семантика AndQuery говорит, что строка является подходящей, если содержит точную последовательность her hair. Вхождения слов в первую строку не удовлетворяют этому условию, хотя они стоят рядом: Alice Emma has long flowing red hair. Her Daddy says а вот во второй строке слова расположены так, как нужно: i when the wind blows through her hair, it looks almost alive Для оставшихся двух вхождений слова her слово hair не является соседним. Таким образом, ответом на запрос является вторая строка текста: (1). Чтобы вычислить результат запроса NameQuery, достаточно получить вектор позиций для указанного слова, преобразовать его в множество неповторяющихся номеров строк и вывести соответствующие строки текста. Ответом на NotQuery служит множество строк, в которых не встречается указанное слово. Так, результатом запроса Pi daddy I служит множество (1,2,4). Для вычисления результата надо знать, сколько всего строк содержится в тексте. (М1 не сохраняли эту информацию, поскольку не были уверены, что она потребуется; к сожалению, недостаточно и этого.) Чтобы упростить обработку NotQuery, полезно сгенерировать множество всех номеров строк текста (0,1,2,3,4,5): теперь для получения результата достаточно с помощью алгоритма set difference() вычислить разность двух множеств. (Ответом на показанный выше запрос будет множество (0,3,5).) Результатом OrQuery является объединение номеров строк, где встречается лев1й или правый операнд. Например, если дан запрос: Pfiery her то результирующим множеством будет (0,1,2,4), которое получается объединением множества (2) для слова fiery и множества (0,1,2,4) для слова her. Такое множество должно быть упорядочено по возрастанию номеров строк и не содержать дубликатов. До сих пор нам удавалось вычислять результат запроса, работая только с множествами неповторяющихся номеров строк. Однако для обработки AndQuery надо принимать во внимание как номер строки, так и номер колонки в каждой паре. Так, указанные в запросе fiery && ( hair bird potato ) fiery && ( ! burr ) NotQuery может быть операндом AndQuery, следовательно, мы должны создать не просто вектор, содержащий по одному элементу для каждой подходящей строки, но и вектор, в котором хранятся позиции. (Мы еще вернемся к этому при рассмотрении функции eval() для класса NotQuery в разделе 17.5.) Таким образом, идентифицирован еще один необходимый член - вектор позиций, ассоциированный с вычислением каждой операции. У нас есть выбор: объявить его членом каждого производного класса или членом абстрактного базового класса Query, наследуемым всеми производными. Объем памяти для хранения этого члена в обоих случаях одинаков. Мы поместим его в базовый класс, локализовав поддержку инициализации и доступа к члену. Решение о том, представлять ли множество неповторяющихся номеров строк (мы называем его разрешающим множеством) в виде члена класса или каждый раз вычислять его, принимает разработчик. Мы предпочли вычислять его по мере необходимости, а затем сохранять адрес для последующего доступа, объявляя этот адрес членом абстрактного базового класса Query. Для вывода найденных строк нам необходимо как разрешающее множество, так и фактический текст, из которого взяты строки. Причем вектор позиций у каждой операции должен быть свой, а экземпляр текста нужен только один. Поэтому мы определим его статическим членом класса Query. (Реализация функции display() опирается только на эти два члена.) Вот результат первой попытки создать абстрактный базовый класс Query (конструкторы, деструктор и копирующий оператор присваивания еще не объявлены: этим мы займемся в разделах 17.4 и 17.6): Если бы не операция AndQuery, нам не пришлось бы вычислять вектор позиций для каждой операции. Но, поскольку операндом AndQuery может быть результат любого запроса, то для каждого приходится вычислять и сохранять не только множество неповторяющихся строк, но и пары (строка, колонка). Рассмотрим следующие запросы: #include <vector> #include <set> #include <string> #include <utility> typedef pair< short, short > location; class Query { public: конструкторы и деструктор обсуждаются в разделе 17.4 / / копирщий конструктор и копирующий обсуждаются в разделе 17.6 оператор присваивания операции для поддержки открытого интерфейса virtual void eval() = 0; virtual void display () const; функции доступа для чтения const set<short> *solution() const; const vector<location> *locations() const { return & loc; } static const vector<string> *text file() {return text file;} protected: set<short>* vec2set( const vector<location>* ); static vector<string> * text file; set<short> * solution; vector<location> loc; inline const set<short> Query:: solution() { return solution ? solution : solution = vec2set( & loc ); Странный синтаксис virtual void eval() = 0; говорит о том, что для виртуальной функции eval() в абстрактном базовом классе Query нет определения: это чисто виртуальная функция, удерживающая место в открытом интерфейсе иерархии классов и не предназначенная для непосредственного вызова из программ!. Вместо нее кажд1й производный класс должен предоставить настоящую реализацию. (Подробно виртуальные функции будут рассматриваться в разделе 17.5.) 17.2.2. Определение производных классов Каждый производный класс наследует данные и функции-члены своего базового класса, и программировать приходится лишь те аспекты, которые изменяют или расширяют его поведение. К примеру, в классе NameQuery необходимо определить реализацию eval() .
|
© 2006 - 2024 pmbk.ru. Генерация страницы: 0.001
При копировании материалов приветствуются ссылки. |