f(*svec.begin()); // ok: передача объекта string; f использует .* для

                  // вызова empty()

f(&svec[0]);      // ok: передача указателя на string; f использует .->

                  // для вызова empty()

Фактически шаблон mem_fn можно считать как будто создающим вызываемый объект с перегруженным оператором вызова функции — один получает тип string*, а другой — string&.

Использование функции bind() для создания вызываемого объекта

Для создания вызываемого объекта из функции-члена можно также использовать функцию bind() (см. раздел 10.3.4):

// связать каждую строку из диапазона

// с неявным первым аргументом empty()

auto it = find_if(svec.begin(), svec.end(),

           bind(&string::empty, _1));

Подобно шаблону function, при использовании функции bind() следует сделать явным обычно неявный параметр функции-члена, представляющий объект, с которым будет работать функция-член. Подобно шаблону mem_fn, первый аргумент вызываемого объекта, создаваемого функцией bind(), может быть либо указателем, либо ссылкой на тип string:

auto f = bind(&string::empty, _1);

f(*svec.begin()); // ok: аргумент - строка f, использует .* для вызова

                  // функции empty()

f(&svec[0]); // ok: аргумент - указатель на строку f использует .->

             // для вызова функции empty()

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

Упражнение 19.18. Напишите функцию, использующую алгоритм count_if() для подсчета количества пустых строк в заданном векторе.

Упражнение 19.19. Напишите функцию, получающую вектор vector и находящую первый элемент, средняя цена которого превосходит заданное значение.

<p>19.5. Вложенные классы</p>

Класс, определяемый в другом классе, называется вложенным классом (nested class) или вложенным типом (nested type). Вложенные классы обычно используются для классов реализации, как, например, класс QueryResult из приложения текстового запроса (см. раздел 12.3).

Имя вложенного класса видимо в области видимости содержащего его класса, но не вне ее. Имя вложенного класса не будет входить в конфликт с тем же именем, объявленным в другой области видимости.

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

В содержащем классе вложенный класс представляет собой член, типом которого является класс. Подобно любому другому члену, содержащий класс задает уровень доступа к этому типу. Вложенный класс, определенный в разделе public содержащего класса, может быть использован везде. Вложенный класс, определенный в разделе protected, доступен только содержащему классу, его производным и дружественным классам. Вложенный класс, определенный в разделе private, доступен лишь для членов содержащего класса и классов, дружественных для него.

Объявление вложенного класса

Класс TextQuery из раздела 12.3.2 определял сопутствующий класс QueryResult. Класс QueryResult жестко связан с классом TextQuery. Класс QueryResult имело бы смысл использовать и для других целей, а не только для результатов операции запроса к объекту класса TextQuery. Для отражения этой жесткой связи сделаем класс QueryResult членом класса TextQuery.

class TextQuery {

public:

 class QueryResult; // вложенный класс будет определен позже

 // другие члены, как в разделе 12.3.2

};

В первоначальный класс TextQuery необходимо внести только одно изменение — объявить о намерении определить класс QueryResult как вложенный. Поскольку класс QueryResult будет типом-членом (см. раздел 7.3.4), его следует объявить прежде, чем использовать. В частности, класс QueryResult следует объявить прежде, чем использовать его как тип возвращаемого значения функции-члена query(). Остальные члены первоначального класса неизменны.

Определение вложенного класса вне содержащего класса

В классе TextQuery класс QueryResult объявлен, но не определен. Подобно функциям-членам, вложенные классы следует объявить в классе, но определен он может быть в или вне класса.

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

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