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;
}