Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
LectionSTL1.docx
Скачиваний:
8
Добавлен:
20.02.2016
Размер:
250.27 Кб
Скачать

Функциональные объекты

Рассмотрим четвертый тип компонентов библиотеки STL, а именно, функциональные объекты. Можно сказать, что функциональный объект – это объект класса, в котором определен метод operator(). Данные объекты являются обобщением указателей на функцию. Напомним, что сама по себе функция не является переменной. Однако можно определить указатели на функции, которые разрешено присваивать, хранить в массивах, назначать полями структур, передавать в функции и возвращать из функций. Функциональные объекты, в некотором смысле, являются обобщением указателей на функцию и предоставляют больше гибкости. Функциональный объект сам по себе является некоторым типом данных и поэтому может передаваться в функцию и возвращаться из функции. Более того, обобщенные алгоритмы STL содержат шаблонные параметры, которые инстанцируются функциональными объектами. Рассмотрим, например, алгоритм, вычисляющий сумму элементов последовательности:

template <typename Inputlterator, typename T> T accumulate(Inputlterator first, Inputlterator last, T init)

{

while (first != last)

init = init + *first; ++first;

return init;

}

Данная функция, будучи вызвана с итераторамиfirst иlast и значениемinit, прибавляет кinit значения в позициях, начиная с first и заканчиваяlast (не включая последнюю), и возвращает получившуюся сумму.

Теперь предположим, что вместо сложения мы захотим использовать умножение, или деление, или какую-либо другую операцию, определенную для того или иного класса и использующую два аргумента. Для этого реализована вторая версия алгоритма:

template <typename Inputlterator, typename T,

typename BinaryOperation>

T accumulate(Inputlterator first, Inputlterator last, T init, BinaryOperation binary_op)

{

while (first != last)

init = binary_op(init,*first); ++first;

return init;

}

Здесь в качестве операции может использоваться любой объект, в котором перегруженный метод operator() принимает два аргумента типа T и возвращает значение, типа T.

Для того, чтобы определять свои функциональные объекты нужно использовать классы, объявленные в стандартной библиотеке и находящиеся в заголовочном файле <functional>. Таких классов два. Первый класс является основой для создания унарных функциональных объектов (унарных функций):

template <typename Arg, typename Result> struct unary_function

{

typedef Arg argument_type; typedef Result result type;

};

И второй класс служит основой для реализации бинарного функционального объекта (бинарной функции):

template <typename Argl, typename Arg2, typename Result> struct binary_function

{

typedef Argl first_argument_type; typedef Arg2 second_argument_type; typedef Result result_type;

};

Класс, создающий унарный функциональный объект должен наследоваться от unary_function, а класс, реализующий бинарный функциональный объект, наследуется от binary_function. В общем случае они должны наследоваться как public, что для структур принято по умолчанию. Это позволяет определять стандартные имена типов для аргументов функции и типа возврата.

Структуры unary_function и binary_function предоставляют typedef для типов аргументов и типа возврата функционального объекта. Эти имена используются некоторыми адаптерами и могут пригодиться в других случаях. Таким образом, следует использовать эти имена и в создаваемом функциональном объекте. Другими словами, вы должны использовать result_type в качестве типа возврата для operator(). Кроме того необходимо использовать argument_type как тип аргумента дляoperator()для унарного функционального объекта и first_argument_type, second argument_type в качестве типов аргументов для бинарного функционального объекта. Таким образом, общая форма operator() выглядит так:

result_type operator (argument_type arg);

result_type operator(first_argument_type argl, second_argument_type arg2);

Функциональный объект не должен создавать побочных эффектов. Другими словами, он не должен предпринимать действий, не связанных с его основным предназначением. Например, функциональный объект, чье назначение - сравнивать два элемента на эквивалентность, не должен модифицировать ни одного из элементов в процессе своей работы.

Приведем пример унарного функционального объекта (унарной функции), который принимает в качестве аргумента переменную x типа double и возвращает значение 1/x также типа double.

class reciprocal:public std::unary_function<double,double>

{

public:

result_type operator() (argument_type val);

};

Ее реализация выглядит так:

std::unary_function<double,double>::result_type reciprocal::operator() (std::unary_function<double,double>::argument_type val)

{

if(val==0.00)

{

return 0.00;

}

else

{

return 1.00/val;

}

}

Следует обратить внимание на синтаксис: тип возвращаемого значения – std::unary_function<double,double>::result_type и тип аргумента – std::unary_function<double,double>::argument_type. И то и другое в данном случае является синонимом типа double.

Экземпляр данного объекта используется как функция:

double x=5.00;

reciprocal fun;

double y=fun(x);

Важно!!! В отличие от функций, использовать функциональный объект можно только после его создания!

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

class midpoint:public std::binary_function<int,int,double>

{

public:

result_type operator()(first_argument_type a1, second_argument_type a2);

};

Соответственно реализация

std::binary_function<int,int,double>::result_type midpoint::operator()(std::binary_function<int,int,double>:: first_аrgument_type a1, std::binary_function<int,int,double>::second_argument_type a2)

{

return static_cast<double>(a1+a2)/2;

}

Тип возвращаемого значения double в данном случае имеет синоним std::binary_function<int,int,double>::result_type, а тип аргументов int – синонимы std::binary_function<int,int,double>::first_argument_type и std::binary_function<int,int,double>::second_argument_type.

Библиотека STL предоставляет некоторые встроенные функциональные объекты. Часть из них реализуют базовые арифметические операции:

STL предоставляет базовые классы функциональных объектов для всех арифметических операторов языка. Функциональность операторов описывается далее: template <typename Т> struct plus;

принимает два операнда типаТ и возвращает их сумму;template <typename Т> struct minus;

принимает два операнда типаТи возвращает результат вычитания второго операнда из первого;template <typename Т> struct multiplies;

принимает два операнда типаТи возвращает их произведение;template <typename Т> struct divides;

принимает два операнда типаТи возвращает результат деления первого операнда на второй; template <typename Т> struct modulus;

принимает два операндахиу, типаТи возвращает результат вычисления х%у.template <typename Т> struct negate;

унарный функциональный объект, который принимает единственный операнд типаТи возвращают значение с обратным знаком.

Эти классы также являются наследниками от класса binary_function, а класс negate – наследник класса unary_function. Например:

template <typename Т> struct multiplies:binary_function<T,T,T>

{ T operator()(const T &a, const T &b)const;};

и

template <typename Т> struct multiplies:unary_function<T,T>

{ T operator()(const T &a)const;};

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

multiplies<int> M;

В библиотеке STL также содержатся функциональные объекты, называемые предикатами. Предикат – функциональный объект, возвращающий значение типа bool. Такими объектами являются операции сравнения и логические операции.

template <typename Т> struct equal_to;

Принимает два параметра,x и у, типаТи возвращаетtrue, еслих==у; в противном случае возвращаетfalse.

template <typename Т> struct not_equal_to;

Принимает два параметра,х и у, типаТи возвращает true, еслих!=у;в противном случае возвращаетfalse.

template <typename Т> struct greater;

Принимает два параметра,х иу, типаТи возвращаетtrue, еслих>у; впротивном случае возвращаетfalse.

template <typename Т> struct less;

Принимает два параметра,х и у, типаТи возвращаетtrue, еслих<у; в противном случае возвращает false.

template <typename Т> struct greater_equal;

Принимает два параметра,х и у, типаТ и возвращаетtrue, если х>=у; в противном случае возвращаетfalse.

Принимает два параметра,х иу, типаТ и возвращает true, еслих>= у, в противном случае возвращает false.

template <typename Т> struct less_equal;

Принимает два параметра,х иу, типаТи возвращает true, еслих<=у; впротивном случае возвращаетfalse.

template <typename T> struct logical_and;

Принимает два параметра,x иу, типа Т и возвращает результат типа bool логической операциии:х&&у.

template <typename Т> struct logical_or;

Принимает два параметра,х иу, типаТи возвращает результат типа bool логической операцииили:х||у.

template <typename Т> struct logical_not;

Принимает один параметрх типаТ и возвращает результат типаbool логической операциине:!х.

11

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]