Как всегда, оператор
>>
возвращает ссылку на поток
*this
(раздел 17.10).
Проверка разделителей проста; мы сравниваем символ с каждым символом из строки, в которой записаны разделители.
bool Punct_stream::is_whitespace(char c)
{
for (int i = 0; i<white.size(); ++i)
if (c==white[i]) return true;
return false;
}
Напомним, что поток
istringstream
обрабатывает обычные разделители (например, символы перехода на новую строку или пробел) по-прежнему, поэтому никаких особых действий предпринимать не надо.
Осталась одна загадочная функция.
Punct_stream::operator bool()
{
return !(source.fail() || source.bad()) && source.good();
}
Обычное использование потока
istream
сводится к проверке результата оператора
>>
. Рассмотрим пример.
while (ps>>s) { /* ... */ }
Это значит, что нам нужен способ для проверки результата выполнения инструкции
ps>>s
, представленного в виде булевого значения. Результатом инструкции
ps>>s
является объект класса
Punct_stream
, поэтому нам нужен способ неявного преобразования класса
Punct_stream
в тип
bool
. Эту задачу решает функция operator
bool()
в классе
Punct_stream
.
Функция-член operator
bool()
определяет преобразование класса
Punct_stream
в тип
bool
. В частности, она возвращает значение
true
, если эта операция над классом
Punct_stream
прошла успешно.
Теперь можем написать программу.
int main()
// вводит текст и создает упорядоченный список всех слов
// из заданного текста, игнорируя знаки пунктуации и регистры,
// а также удаляя дубликаты из полученного результата
{
Punct_stream ps(cin);
ps.whitespace(";:,.?!()\"{}<>/&$@#%^*|~"); // \" в строке
// означает "
ps.case_sensitive(false);
cout << "Пожалуйста, введите слова \n";
vector<string> vs;
string word;
while (ps>>word) vs.push_back(word); // ввод слов
sort(vs.begin(),vs.end()); // сортировка в лексикографическом
// порядке
for (int i=0; i<vs.size(); ++i) // запись в словарь
if (i==0 || vs[i]!=vs[i–1]) cout << vs[i] << endl;
}
Этот код создает упорядоченный список введенных слов. Инструкция
if (i==0 || vs[i]!=vs[i–1])
удаляет дубликаты. Если в программу ввести слова
There are only two kinds of languages: languages that people complain
about, and languages that people don’t use.
то результат ее работы будет выглядеть следующим образом:
about
and
are
complain
don’t
kind
languages
of
only
people
that
there
two
use
Почему мы получили на выходе
don’t
, а не
dont
? Потому что оставили апостроф за пределами списка разделителей
whitespace()
.
Внимание: класс
Punct_stream
во многом похож на класс
istream
, но на самом деле отличается от него. Например, мы не можем проверить его состояние с помощью функции
rdstate()
, функция
eof()
не определена, и нет оператора
>>
, который вводит целые числа. Важно отметить, что мы не можем передать объект класса
Punct_stream
в качестве аргумента функции, ожидающей поток
istream
. Можно ли определить класс
Punct_istream
, который в точности повторял бы поведение класса
istream
? Можно, но у вас пока нет достаточного опыта программирования, вы еще не освоили основы проектирования и не знаете всех возможностей языка (если впоследствии вы вернетесь к этой задаче, то сможете реализовать буферы потоков на уровне профессионала).
Легко ли читать определение класса
Punct_stream
? Понятны ли вам объяснения? Могли бы вы самостоятельно написать такую программу? Еще несколько дней назад вы были новичком и честно закричали бы: “Нет, нет! Никогда!” или “Нет, нет! Вы что, с ума сошли? Очевидно, что ответ на поставленный вопрос отрицательный”. Цель нашего примера заключается в следующем:
• показать реальную задачу и способ ее решения;