Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
C++ для начинающих.pdf
Скачиваний:
183
Добавлен:
01.05.2014
Размер:
3.97 Mб
Скачать

Полиморфизм подтипов позволяет написать ядро приложения так, что оно не будет зависеть от конкретных типов, которыми мы манипулируем. Мы программируем открытый интерфейс базового класса придуманной нами абстракции, пользуясь только ссылками и указателями на него. При работе программы будет определен фактический тип адресуемого объекта и вызвана подходящая реализация открытого интерфейса.

Нахождение (или разрешение) нужной функции во время выполнения называется динамическим связыванием (dynamic binding) (по умолчанию функции разрешаются статически во время компиляции). В C++ динамическое связывание поддерживается с помощью механизма виртуальных функций класса. Полиморфизм подтипов и динамическое связывание формируют основу объектно-ориентированного программирования, которому посвящены следующие главы.

В главе 17 рассматриваются имеющиеся в C++ средства поддержки объектноориентированного программирования и изучается влияние наследование на такие механизмы, как конструкторы, деструкторы, почленная инициализация и присваивание; для примера разрабатывается иерархия классов Query, поддерживающая систему текстового поиска, введенную в главе 6.

Темой главы 18 является изучение более сложных иерархий, возможных за счет использования множественного и виртуального наследования. С его помощью мы развернем шаблон класса из главы 16 в трехуровневую иерархию.

В главе 19 обсуждается идентификация типов во время выполнения (RTTI), а также изучается вопрос о влиянии наследования на разрешение перегруженных функций. Здесь мы снова обратимся к средствам обработки исключений, чтобы разобраться в иерархии классов исключений, которую предлагает стандартная библиотека. Мы покажем также, как написать собственные такие классы.

Глава 20 посвящена углубленному рассмотрению библиотеки потокового ввода/вывода iostream. Эта библиотека представляет собой иерархию классов, поддерживающую как виртуальное, так и множественное наследование.

17

17. Наследование и подтипизация классов

В главе 6 для иллюстрации обсуждения абстрактных контейнерных типов мы частично реализовали систему текстового поиска и инкапсулировали ее в класс TextQuery. Однако мы не написали к ней никакой вызывающей программы, отложив реализацию поддержки формулирования запросов со стороны пользователя до рассмотрения объектно-ориентированного программирования. В этой главе язык запросов будет реализован в виде иерархии классов Query с одиночным наследованием. Кроме того, мы модифицируем и расширим класс TextQuery из главы 6 для получения полностью интегрированной системы текстового поиска.

Программа для запуска нашей системы текстового поиска будет выглядеть следующим образом:

#include

"TextQuery

.h"

int main()

{

TextQuery tq;

tq.build_up_text()

;

tq.query_text();

}

build_text_map() – это слегка видоизмененная функция-член doit() из главы 6. Ее основная задача – построить отображение для хранения позиций всех значимых слов текста. (Если помните, мы не храним семантически нейтральные слова типа союзов if, and, but и т.д. Кроме того, мы заменяем заглавные буквы на строчные и устраняем суффиксы, обозначающие множественное число: например, testifies преобразуется в testify, а marches в march.) С каждым словом ассоциируется вектор позиций, в котором хранятся номера строки и колонки каждого вхождения слова в текст.

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

Enter a query - please separate each item by a space.

Terminate query (or session) with a dot( . ).

==> fiery && ( bird || shyly )

fiery ( 1 ) lines match bird ( 1 ) lines match shyly ( 1 ) lines match

( bird || shyly ) ( 2 ) lines match

fiery && ( bird || shyly ) ( 1 ) lines match

Requested query: fiery && ( bird || shyly )

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

Внашей системе мы выбрали следующий язык запросов:

одиночное слово, например Alice или untamed. Выводятся все строки, в которых оно встречается, причем каждой строке предшествует ее номер, заключенный в скобки. (Строки печатаются в порядке возрастания номеров). Например:

==> daddy

daddy ( 3 ) lines match

Requested query: daddy

( 1 ) Alice Emma has long flowing red hair. Her Daddy says

( 4 ) magical but untamed. "Daddy, shush, there is no such thing," ( 6 ) Shyly, she asks, "I mean, Daddy, is there?"

∙ запрос “НЕ”, формулируемый с помощью оператора !. Выводятся все строки, где не встречается указанное слово. Например, так формулируется отрицание запроса 1:

==> ! daddy

daddy ( 3 ) lines match ! daddy ( 3 ) lines match

Requested query: ! daddy

( 2 ) when the wind blows through her hair, it looks almost alive, ( 3 ) like a fiery bird in flight. A beautiful fiery bird, he tells her,

( 5 ) she tells him, at the same time wanting him to tell her more.

запрос “ИЛИ”, формулируемый с помощью оператора ||. Выводятся все строки, в которых встречается хотя бы одно из двух указанных слов:

==> fiery || untamed

fiery ( 1 ) lines match untamed ( 1 ) lines match

fiery || untamed ( 2 ) lines match Requested query: fiery || untamed

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

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

запрос “И”, формулируемый с помощью оператора &&. Выводятся все строки, где оба указанных слова встречаются, причем располагаются рядом. Сюда входит и случай, когда одно слово является последним в строке, а другое – первым в следующей:

==> untamed && Daddy

untamed ( 1 ) lines match daddy ( 3 ) lines match

untamed && daddy ( 1 ) lines match

Requested query: untamed && daddy

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

Эти элементы можно комбинировать:

fiery && bird || shyly

Однако обработка производится слева направо, и все элементы имеют одинаковые приоритеты. Поэтому наш составной запрос интерпретируется как fiery bird

ИЛИ shyly, а не как fiery bird ИЛИ fiery shyly:

==> fiery && bird || shyly