Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
STL5 / lab8-functors / lab8-STL-functor.doc
Скачиваний:
9
Добавлен:
10.04.2015
Размер:
259.07 Кб
Скачать

Void Print() const

{

cout << name << " is " << age << "years old" << endl;

}

// Неконстантный метод класса без аргументов

Void GrowOld()

{

age++;

}

// Константный метод класса с одним аргументом, возвращает bool

bool IsOlder(const Person& person) const

{

return (age > person.age);

}

// Константный метод класса без аргументов, возвращающий bool

bool IsPensioner() const

{

return (age > 60);

}

private:

string name;

int age;

};

int main (int, char**)

{ // Заполним вектор объектами

vector<Person> vec;

vec.push_back(Person("John", 67));

vec.push_back(Person("Vova", 15));

vec.push_back(Person("Lenochka", 3));

vec.push_back(Person("Igor", 60));

vec.push_back(Person("Mary", 24));

vec.push_back(Person("Vasen'ka", 6));

// Распечатаем все объекты, адаптер создан явно (неудобно)

// адаптируем константный метод без аргументов

// for_each(vec.begin(),vec.end(),

// const_mem_fun_ref_t<void,Person>(&Person::Print));

// Тоже, адаптер создан с помощью функции-помощника

for_each(vec.begin(),vec.end(),mem_fun_ref(&Person::Print));

cout << "--------------------------" << endl;

// Отсортируем все объекты, адаптер создан явно (неудобно)

// адаптируем константный метод с одним аргументом

// sort(vec.begin(),vec.end(),

// const_mem_fun1_ref_t<bool,Person,const Person&>(&Person::IsOlder));

// Тоже, адаптер создан с помощью функции-помощника

sort(vec.begin(),vec.end(),mem_fun_ref(&Person::IsOlder));

for_each(vec.begin(),vec.end(),mem_fun_ref(&Person::Print));

cout << "--------------------------" << endl;

// Удалим объекты удовлетворяющие предикату (предикат – метод класса)

// Объект адаптера создан явно (неудобно)

// vec.erase(remove_if(vec.begin(),vec.end(),

// const_mem_fun_ref_t<bool,Person>(&Person::IsPensioner)),

// vec.end());

// Тоже, адаптер создан с помощью функции-помощника

vec.erase(remove_if(vec.begin(),vec.end(),

mem_fun_ref(&Person::IsPensioner)),

vec.end());

for_each(vec.begin(),vec.end(),mem_fun_ref(&Person::Print));

cout << "--------------------------" << endl;

// Адаптер для неконстантного метода без аргументов создается явно

// for_each(vec.begin(),vec.end(),

// mem_fun_ref_t<void,Person>(&Person::GrowOld));

// Тоже, адаптер создан с помощью функции-помощника

for_each(vec.begin(),vec.end(),mem_fun_ref(&Person::GrowOld));

for_each(vec.begin(),vec.end(),mem_fun_ref(&Person::Print));

cout << "--------------------------" << endl;

return 0;

}

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

Адаптеры членов классов (2)

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

class Object

{

public:

bool Test(void);

...

};

...

vec.push_back(new Object(. . .));

. . .

vec.push_back(new Object(. . .));

vec.erase(remove_if(vec.begin(),vec.end(),

что-то_похожее_на_mem_fun_ref(&Person::Test)),

vec.end());

Хочется иметь возможность применять адаптер аналогичный mem_fun_ref_t для вызова методов класса, который принимал бы в качестве аргумента не ссылку на объект, а указатель.

В данном случае использование mem_fun_ref_t невозможно, так как он использует для вызова функции object.*Predicate() форму записи, а в случае с указателями на объект класса необходимо применять object->*Predicate(). Стандартная библиотека содержит группу адаптеров mem_fun_t, которая может быть применена в этом случае. Они практически аналогичны рассмотренным выше адаптерам mem_fun_ref_t. Ниже приведены их объявления и возможная реализация, существенные отличия выделены жирным шрифтом.

template<class Result, class T>

class mem_fun_t : public unary_function<T*,Result>

{

public:

explicit mem_fun_t(Result (T::*Fun)()): Function(Fun) {}

Result operator()(T* x) const

{

return ((x->*Function)());

}

private:

Result(T::*Function)();

};

template<class Result, class T, class Arg>

class mem_fun1_t : public binary_function<T*,Arg,Result>

{

public:

explicit mem_fun1_t(Result (T::*Fun)(Arg)): Function(Fun) {}

Result operator()(T* x, A y) const

{

return ((x->*Function)(y));

}

private:

Result(T::*Function)(A y);

};

template<class Result, class T>

class const_mem_fun_t : public unary_function<T*,Result>

{

public:

explicit const_mem_fun_t(Result (T::*Fun)() const): Function(Fun) {}

Result operator()(const T* x) const

{

return ((x->*Function)());

}

private:

Result(T::*Function)() const;

};

template<class Result, class T, class Arg>

class const_mem_fun1_t : public binary_function<T*,Arg,Result>

{

public:

explicit const_mem_fun1_t(Result (T::*Fun)(Arg) const): Function(Fun) {}

Result operator()(const T* x, A y) const

{

return ((x->*Function)(y));

}

private:

Result(T::*Function)(A y) const;

};

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

template<class Result, class T> inline

mem_fun_t<Result,T> mem_fun(Result (T::*p)())

{

return (mem_fun_t<Result,T>(p));

}

template<class Result, class T, class Arg> inline

mem_fun1_t<Result,T,Arg> mem_fun(Result (T::*p)(Arg))

{

return (mem_fun1_t<Result,T,Arg>(p));

}

template<class Result, class T> inline

const_mem_fun_t<Result,T> mem_fun(Result (T::*p)() const)

{

return (const_mem_fun_t<Result,T>(p));

}

template<class Result, class T, class Arg> inline

const_mem_fun1_t<Result,T,Arg> mem_fun(Result (T::*p)(Arg) const)

{

return (const_mem_fun1_t<Result,T,Arg>(p));

}

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

#include <iostream>

#include <algorithm>

#include <functional>

#include <vector>

#include <string>

using namespace std;

class Shape

{

public:

virtual void Draw() const = 0;

};

//----------------------------

class Circle : public Shape

{

public:

virtual void Draw() const;

};

void Circle::Draw() const

{

cout << "Circle is drawing itself" << endl;

}

//----------------------------

class Square : public Shape

{

public:

virtual void Draw() const;

};

void Square::Draw() const

{

cout << "Square is drawing itself" << endl;

}

//----------------------------

class Ellipse: public Shape

{

public:

virtual void Draw() const;

};

void Ellipse::Draw() const

{

cout << "Ellipse is drawing itself" << endl;

}

int main (int, char**)

{

vector<Shape*> vec;

vec.push_back(new Circle());

vec.push_back(new Ellipse());

vec.push_back(new Ellipse());

vec.push_back(new Ellipse());

vec.push_back(new Circle());

vec.push_back(new Square());

vec.push_back(new Circle());

vec.push_back(new Square());

// Явное создание объекта адаптера

// for_each(vec.begin(),vec.end(),

// const_mem_fun_t<void,Shape>(&Shape::Draw));

// Использование функции-помощника

for_each(vec.begin(),vec.end(),mem_fun(&Shape::Draw));

return 0;

}

Соседние файлы в папке lab8-functors