Программирование. Принципы и практика использования C++ Исправленное издание, стр. 164

Как всегда, оператор

>>
возвращает ссылку на поток
*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()
.

 

Программирование. Принципы и практика использования C++ Исправленное издание - _003.png
 Внимание: класс
Punct_stream
во многом похож на класс
istream
, но на самом деле отличается от него. Например, мы не можем проверить его состояние с помощью функции
rdstate()
, функция
eof()
не определена, и нет оператора
>>
, который вводит целые числа. Важно отметить, что мы не можем передать объект класса
Punct_stream
в качестве аргумента функции, ожидающей поток
istream
. Можно ли определить класс
Punct_istream
, который в точности повторял бы поведение класса
istream
? Можно, но у вас пока нет достаточного опыта программирования, вы еще не освоили основы проектирования и не знаете всех возможностей языка (если впоследствии вы вернетесь к этой задаче, то сможете реализовать буферы потоков на уровне профессионала).

 

Программирование. Принципы и практика использования C++ Исправленное издание - _001.png
 Легко ли читать определение класса
Punct_stream
? Понятны ли вам объяснения? Могли бы вы самостоятельно написать такую программу? Еще несколько дней назад вы были новичком и честно закричали бы: “Нет, нет! Никогда!” или “Нет, нет! Вы что, с ума сошли? Очевидно, что ответ на поставленный вопрос отрицательный”. Цель нашего примера заключается в следующем: 

• показать реальную задачу и способ ее решения;