Иллюстрированный самоучитель по Visual Studio .NET

Контейнеры библиотеки STL. Последовательности типа vector.

Предикаты и функциональные объекты

Предикатом, как определено в курсе математической логики, называется любая функция многих переменных, областью значений которой является множество {false, true} или {0, 1}. Покажем, как можно отсортировать по имени контейнер объектов класса Man, который мы определили в этом уроке выше. Алгоритм sort по умолчанию использует для сортировки бинарное отношение, задаваемое операцией operator< (). Так как в классе Man эта операция была определена в виде метода класса, то алгоритм справится с поставленной задачей. Однако если мы захотим изменить порядок и отсортировать последовательность объектов по возрасту, то нам придется воспользоваться другим отношением. Решить эту задачу можно двумя способами:

  • использовать свою собственную функцию-предикат, которая определяет порядок следования объектов;
  • использовать конструкцию, называемую функциональным объектом.

Первый способ реализуется путем создания глобальной функции, на вход которой поступают два сравниваемых объекта, а на выходе должен быть результат их сравнения, например типа bool. Второй способ реализуется созданием функционального объекта (function object или functor), являющегося структурой, в которой определена операция operator (). Этот термин, однако, используется для обозначения не только описанного объекта, но и для любого другого, который можно вызвать так, как вызывают функцию. Собственно, кроме описанного случая, роль функционального объекта может выполнять обычная функция и указатель на функцию.

Покажем, как создать предикат. В описание класса Man следует добавить объявление внешней функции в качестве friend-объекта, так как в ее теле будут анализироваться private-данные класса Man. Добавьте в класс Man такое описание:

//======== Предикат, задающий отношение порядка
friend bool LessAge (Mans a, Man& b);

Затем вставьте коды этой функции после объявления класса, но до тела функции main:

bool LessAge (Man& a, Man& b)
{
//======== Сравниваем по возрасту
return a.m_Age < b.m_Age;
}

Теперь можно создать контейнер объектов класса Man и убедиться в возможности его сортировки двумя способами. В момент создания контейнер может быть инициализирован элементами обычного массива. Ниже мы показываем, как это сделать:

void main ()
{
//======== Массив объектов класса Man
Man ar[] =
{
Man("Mary Poppins",36),
Man("Joe Doe",30),
Man("Joy Amore",18),
Man("Zoran Todorovitch",27)
};
uint size = sizeof (ar) /sizeof (Man);
//======== Создаем контейнер на основе массива
vector<Man> men(ar, ar+size); pr(men,"Man Vector");
//======== Реверсируем обычный массив
reverse(ar, ar+size);
cout << "\n\tAfter reversing the array\n\n";
for (uint i=0; i<size; i++)
cout << i+1 << ". " << ar[i] << '\n';
//======== Сортиуем по умолчанию
sort (men.begin (), men.endO);
pr(men,"After default sort");
//======== Используем предикат
sort (men.begin (), men.endO, LessAge);
pr(men,"After predicate LessAge sort");
cout << "\n\n";
}
Если Вы заметили ошибку, выделите, пожалуйста, необходимый текст и нажмите CTRL + Enter, чтобы сообщить об этом редактору.