Контейнеры библиотеки 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"; }