В качестве примера определим класс, выводящий строковый аргумент. По умолчанию класс будет писать в поток cout и выводить пробел после каждой строки. Позволим также пользователям класса предоставлять другой поток для записи и другой разделитель. Этот класс можно определить следующим образом:

class PrintString {

public:

 PrintString(ostream &o = cout, char c = ' '):

  os(o), sep(c) { }

 void operator()(const string &s) const { os << s << sep; }

private:

 ostream &os // поток для записи

 char sep;    // символ завершения после каждого вывода

};

У класса есть конструктор, получающий ссылку на поток вывода, и символ, используемый как разделитель. Как аргументы по умолчанию (см. раздел 6.5.1) для этих параметров используется поток cout и пробел. Тело оператора вызова функции использует эти члены при выводе данной строки.

При определении объектов класса PrintString можно использовать аргументы по умолчанию или предоставлять собственные значения для разделителя или потока вывода:

PrintString printer; // использует аргументы по умолчанию; вывод в cout

printer(s);          // выводит s и пробел в cout

PrintString errors(cerr, '\n');

errors(s);           // выводит s и новую строку в cerr

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

for_each(vs.begin(), vs.end(), PrintString(cerr, '\n'));

Третий аргумент алгоритма for_each() является временным объектом типа PrintString, инициализируемый потоком cerr и символом новой строки. Вызов функции for_each() выводит каждый элемент vs в поток cerr, разделяя их новой строкой.

Упражнения раздела 14.8

Упражнение 14.33. Сколько операндов может иметь перегруженный оператор вызова функции?

Упражнение 14.34. Определите класс объекта функции для выполнения действий условного оператора: оператор вызова этого класса должен получать три параметра. Он должен проверить свой первый параметр и, если эта проверка успешна, возвратить свой второй параметр; в противном случае он должен возвратить свой третий параметр.

Упражнение 14.35. Напишите класс, подобный классу PrintString, который читает строку из потока istream и возвращает строку, представляющую прочитанное. При неудаче чтения следует возвратить пустую строку.

Упражнение 14.36. Используя класс из предыдущего упражнения, организуйте чтение со стандартного устройства ввода, сохраняя каждую строку в векторе как элемент.

Упражнение 14.37. Напишите класс, проверяющий равенство двух значений. Используйте этот объект и библиотечные алгоритмы для написания кода замены всех экземпляров заданного значения в последовательности.

<p>14.8.1. Лямбда-выражения — объекты функции</p>

В предыдущем разделе объект PrintString использовался как аргумент в вызове функции for_each(). Это похоже на программу, написанную в разделе 10.3.2, где использовалось лямбда-выражение. Написанное лямбда-выражение компилятор преобразовывает в безымянный объект безымянного класса (см. раздел 10.3.3). Классы, созданные из лямбда-выражения, содержат перегруженный оператор вызова функции. Рассмотрим, например, лямбда-выражение, передававшееся как последний аргумент функции stable_sort():

// сортировать слова по размеру, поддерживая алфавитный порядок среди

// слов того же размера

stable_sort(words.begin(), words.end(),

            [](const string &a, const string &b)

             { return a.size() < b.size();});

Это действует как безымянный объект класса, который выглядел бы примерно так:

class ShorterString {

public:

 bool operator()(const string &s1, const string &s2) const

  { return s1.size() < s2.size(); }

};

Перейти на страницу:

Похожие книги