Какова общая идея делегата в C ++? Что они, как они используются и для чего они используются?
Я хотел бы сначала узнать о них «черным ящиком», но немного информации о внутренностях этих вещей тоже было бы здорово.
Это не C ++ в его самом чистом или чистом виде, но я замечаю, что кодовая база, где я работаю, имеет их в изобилии. Я надеюсь понять их достаточно, так что я могу просто использовать их и не нужно углубляться в ужасную ужасность вложенных шаблонов.
Эти две статьи The Code Project объясняют, что я имею в виду, но не очень кратко:
c++
delegates
delegation
SirYakalot
источник
источник
delegate
не является распространенным именем на языке С ++. Вы должны добавить некоторую информацию к вопросу, чтобы включить контекст, в котором вы ее прочитали. Обратите внимание, что хотя шаблон может быть общим, ответы могут отличаться, если вы говорите о делегате в целом или в контексте C ++ CLI или любой другой библиотеки, в которой есть конкретная реализация делегата .Ответы:
У вас есть невероятное количество вариантов для достижения делегатов в C ++. Вот те, которые пришли мне в голову.
Вариант 1: функторы:
Функциональный объект может быть создан путем реализации
operator()
Вариант 2: лямбда-выражения (только C ++ 11 )
Вариант 3: функциональные указатели
Вариант 4: указатель на функции-члены (самое быстрое решение)
См. Fast C ++ Delegate (в проекте кода ).
Вариант 5: std :: function
(или
boost::function
если ваша стандартная библиотека не поддерживает его). Это медленнее, но это наиболее гибкий.Вариант 6: привязка (используя std :: bind )
Позволяет заранее установить некоторые параметры, например, удобно вызывать функцию-член.
Вариант 7: шаблоны
Примите что угодно, если оно соответствует списку аргументов.
источник
std::bind
, и оба действительно делают одно и то же, за исключением того, что лямбды не полиморфны в том смысле, что они могут принимать разные типы аргументов.binding
в моем списке). Вы не можете достичь этого с помощью функциональных указателей.Делегат - это класс, который оборачивает указатель или ссылку на экземпляр объекта, метод-член класса этого объекта, который вызывается для этого экземпляра объекта, и предоставляет метод для запуска этого вызова.
Вот пример:
источник
Execute()
который инициирует вызов функции на объекте, который переносит делегат.Потребность в реализациях делегатов C ++ является длительным затруднением для сообщества C ++. Каждый программист C ++ хотел бы иметь их, поэтому они в конечном итоге используют их, несмотря на то, что:
std::function()
использует операции кучи (и недоступен для серьезного встроенного программирования).Все другие реализации идут на уступки либо к переносимости, либо к стандартному соответствию в большей или меньшей степени (пожалуйста, проверьте, осмотрев различные реализации делегатов здесь и в проекте кода). Мне еще предстоит увидеть реализацию, которая не использует дикие reinterpret_casts, «прототипы» вложенного класса, которые, как мы надеемся, выдают указатели на функции того же размера, что и передаваемый пользователем, трюки компилятора, такие как сначала forward forward, затем затем typedef, затем снова объявляют, на этот раз наследование от другого класса или аналогичных теневых методов. Несмотря на то, что это большое достижение для разработчиков, которые его создали, это все еще печальное свидетельство того, как развивается С ++.
Лишь в редких случаях указывается, что в настоящее время более 3 стандартных версий C ++ делегаты не были должным образом рассмотрены. (Или нехватка языковых функций, которые допускают прямую реализацию делегатов.)
Благодаря тому, как лямбда-функции C ++ 11 определяются стандартом (у каждой лямбда-функции есть анонимный, различный тип), ситуация только улучшилась в некоторых случаях использования. Но для случая использования делегатов в (DLL) библиотечных API, одни только лямбды не могут быть использованы. Обычный способ - сначала упаковать лямбда-выражение в функцию std ::, а затем передать ее через API.
источник
std::function
не всегда динамически распределяетсяОчень просто, делегат обеспечивает функциональность того, как ДОЛЖЕН работать указатель на функцию. Есть много ограничений указателей функций в C ++. Делегат использует некоторую скрытность шаблона для создания функции-указателя-типа-класса-класса, которая работает так, как вы этого хотите.
то есть - вы можете установить их так, чтобы они указывали на данную функцию, и вы можете передавать их и вызывать их в любое время и в любом месте.
Здесь есть несколько очень хороших примеров:
источник
Опция для делегатов в C ++, которая здесь не упоминается, заключается в том, чтобы сделать это в стиле C, используя функцию ptr и аргумент контекста. Вероятно, это та же самая схема, которую многие, задавая этот вопрос, пытаются избежать. Но шаблон является переносимым, эффективным и может использоваться во встроенном коде и коде ядра.
источник
Windows Runtime эквивалент функционального объекта в стандарте C ++. Можно использовать всю функцию в качестве параметра (фактически это указатель на функцию). В основном используется в сочетании с событиями. Делегат представляет собой контракт, который обработчики событий очень выполняют. Это облегчает работу указателя функции.
источник