Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Методичка ПИ_ИКТ Программирование по С++ (1 семестр) _Хотов.docx
Скачиваний:
1
Добавлен:
01.07.2025
Размер:
5.83 Mб
Скачать

Использование с указателями на функции члены

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

class GraphicsObject

{

public:

void Draw(Canvas* canvas, DrawModes mode);

};

// Объявляем коллекцию объектов этого класса:

std::list<GraphicsObject*> GraphObjects;

// А теперь нам нужно отрисовать все объекты коллекции на заданном канвасе

std::for_each(GraphObjects.begin(), GraphObjects.end(); ……..);

при использовании чистого STL нам бы пришлось писать свой собственный функтор, вызывающий у переданного объекта метод Draw с заданными параметрами. Но можно воспользоваться boost::bind:

std::for_each(GraphObjects.begin(), GraphObjects.end(),

boost::bind(&GraphObject::Draw, _1, canvas, mode));

в результате чего мы получаем требуемый результат. У всех объектов коллекции вызывается метод Draw, которому передаются параметры canvas и mode. При использовании указателя на функцию-член класса необходимо помнить о том, что первым параметром ей должен передаваться указатель на объект, для которого эта функция должна вызываться. В приведенном примере мы указываем, что метод должен вызываться у переданного в bind единственного параметра. Но никто не мешает нам в качестве первого передаваемого параметра указать this, или любой другой указатель. Но, как говориться в современных набивших оскомину рекламах, это еще не все.

Использование с указателем на член данных

Помимо указателей на члены-функции можно использовать указатели на члены данных. Синтаксис подобный и правила использования при этом почти такие же. Возьмем задачу. Есть структура и вектор ее экземпляров:

struct Point

{

int x;

int y;

};

std::vector<Point> PointsArray;

Теперь надо удалить из этого массива все элементы, у которых координата x равна нулю. Сделать это просто:

std::remove_if(PointsArray.begin(), PointsArray.end(),

boost::bind(std::equal_to<int>(), boost::bind(&Point::x, _1), 0));

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

Каскадное использование связывателей

Связыватели могут вкладываться друг в друга. Один из вариантов такого вкладывания проиллюстрирован предыдущем примером. Единственное, что в этом случае надо «держать в голове» - это то, что плейсхолдеры, вне зависимости от того, в каком bind'ере (по уровню вложенности) они находятся, «адресуют» параметры самого внешго binder'а. Усложним предыдущий пример. Нужно выбросить все точки, имеющие нулевые координаты:

std::remove_if( PointsArray.begin(), PointsArray.end(), boost::bind(

std::logical_and(),

boost::bind(std::equal_to<int>(), boost::bind(&Point::x, _1), 0),

boost::bind(std::equal_to<int>(), boost::bind(&Point::y, _1), 0)

)

));

Это хотя и работает так, как хочется, но выглядит слишком наворочено. По этому начиная с версии 1.33 в boost::bind появилась новая возможность -

Перегруженные операторы

Для упрощения приведенных выше многоэтажных конструкций для boost::bind (начиная с версии 1.33 boost'а) перегружены следующие операторы: !, ==, !=, <, ?, > и >=. Таким образом, приведенное выше выражение упрощается до:

std::remove_if( PointsArray.begin(), PointsArray.end(), boost::bind(

boost::bind(&Point::x, _1) == 0 && boost::bind(&Point::y, _1) == 0)

));