Использует ли обратные вызовы в С++ увеличение связи?
Q1. Почему используются функции обратного вызова?
Q2. Являются ли обратные вызовы злыми? Развлечения для тех которые знают, для других - кошмар.
Q3. Любая альтернатива обратного вызова?
Ответы
Ответ 1
Независимо от того, "используя обратные вызовы в С++ увеличивают связь" или нет, я предлагаю использовать стиль обработчика событий, особенно события, подобные событиям. Например, конкретный шаблон проектирования вместо концепции обратного вызова, как показано ниже:
class MyClass
{
public:
virtual bool OnClick(...) = 0;
virtual bool OnKey(...) = 0;
virtual bool OnTimer(...) = 0;
virtual bool OnSorting(...) = 0
...
};
Вы все еще можете считать, что перечисленные выше функции являются обратными вызовами, но, рассматривая их как известный шаблон проектирования, вы не будете путаться, потому что вы выполняете OO и записываете С++.
Effo UPD @2009nov13 -
Типичные случаи: Framework, система событий или модель параллельного программирования и т.д. Следующие примеры должны быть полезными.
Рамки контролируют общий поток, как гласит Голливудский принцип: "Не звоните нам, мы позвоним вам". (что означает "обратный вызов" ), в то время как для нормальной функции или lib, вызывающий управляет потоком.
Известная структура C - это ядро Linux, а писатель Linux-драйверов знает, что он/она будет реализовывать "struct file_operations" в нем. "read()" означает OnRead() и "write()" означает OnWrite ( ) и т.д.
struct file_operations {
struct module *owner;
loff_t (*llseek) (struct file *, loff_t, int);
ssize_t (*read) (struct file *, char __user *, size_t, loff_t *);
ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *);
ssize_t (*aio_read) (struct kiocb *, const struct iovec *, unsigned long, loff_t);
ssize_t (*aio_write) (struct kiocb *, const struct iovec *, unsigned long, loff_t);
...
};
Но самый простой пример структуры должен быть:
The Framework | A developer to do
----------------------------+--------------------------------------
| class MyClass : public Actor
| {
| public:
pApplication->Init(...); | virtual bool OnInit(...) {}
pApplication->Run(...); | virtual int OnRun(...) {}
pApplication->Quit(...); | virtual void OnQuit(...) {}
| ...
| };
и pApplication- > Init() вызовет pActor- > OnInit, а pApplication- > Run() вызовет pActor- > OnRun() и так далее. Большинство разработчиков графических интерфейсов Windows испытали внедрение OnMouseClick() или OnButtonPress() и т.д.
Я согласен с другими ответами этой темы, что они дают правильное объяснение на основе соответствующей точки зрения, например, обработчики в многоуровневом подходе, обобщенные обратные вызовы или асинхронные операции и т.д. Это зависит от вас, что идея подходит для вас.
Ответ 2
Обратные вызовы уменьшают связь - вызываемая сторона передается некоторым указателем и не знает, что за ней. Обратные вызовы - такое удачное решение, что они очень распространены.
Например, посмотрите sqlite3_exec(). Вы даете ему запрос и, возможно, обратный вызов. Он выполняет запрос и вызывает обратный вызов для каждой строки по мере ее получения. Теперь SQLite-бизнес выполняет запрос быстро и с низким потреблением ресурсов, и только ваш бизнес обрабатывает извлеченные результаты по своему усмотрению. Вы можете добавить их в контейнер и обработать все позже, или вы можете обрабатывать их сразу один за другим, или вы можете отправить их по факсу где-нибудь и ожидать, что другая сторона отправит их по факсу - SQLite не волнует, он полностью абстрагируется и может просто выполнять свою работу.
Ответ 3
Q3. Любая альтернатива обратного вызова?
Я предпочитаю функторную форму обратного вызова. например такого рода вещи:
class WidgetContainerOrProcessorOfSomeSort
{
public:
struct IWidgetFunctor
{
virtual bool operator()( const Widget& thisWidget )=0;
};
....
bool ProcessWidgets( IWidgetFunctor& callback )
{
.....
bool continueIteration = callback( widget[ idxWidget ] );
if ( !continueIteration ) return false;
.....
}
};
struct ShowWidgets : public WidgetContainerOrProcessorOfSomeSort::IWidgetFunctor
{
virtual bool operator(){ const Widget& thisWidget }
{
thisWidget.print();
return true;
}
};
WidgetContainterOrProcessorOfSomeSort wc;
wc.ProcessWidgets( ShowWidgets() );
Это всегда кажется немного многословным для простых образцов, но в реальном мире я нахожу его намного проще, чем пытаться точно запомнить, как создавать объявления с указателями сложных функций: -)
Ответ 4
- Обратные вызовы уменьшают связь, поскольку они позволяют вам писать код, который вызывает функцию, которая может быть изменена.
- Обратные вызовы не являются злыми, просто если вы используете необработанные указатели функций, все может стать беспорядочным.
- Альтернативы обратным вызовам не существует, но есть альтернативы использованию необработанных указателей функций.
Сообщение, указывающее на Boost, было сделано ранее для Boost.Function. Если вы ищете более общее решение для обратных вызовов, например несколько функций, связанных с одним и тем же обратным вызовом, или что-то в этом роде, рассмотрите возможность использования Boost.Signals. Название происходит от сигналов и слотов, так как некоторые люди ссылаются на обратные вызовы в наши дни, особенно для графических интерфейсов.
Ответ 5
-
Обратные вызовы используются, например, для вызова асинхронных операций, то есть кода, который выполняется в другом потоке, в то время как вызывающий абонент выполняет свой собственный путь. Вам нужен какой-то механизм, чтобы знать, когда завершилась асинхронная операция.
-
Почему они были злыми? Как и в случае с любым другим ресурсом программирования, они полезны при разумном использовании. На самом деле Windows API и .NET Framework, например, используют обратные вызовы широко.
-
Не знаю о С++, но в мире .NET объекты и события syncronization являются альтернативами.
Ответ 6
Q1. Обратные вызовы необходимы, если вы используете многоуровневый подход, в котором более высокие уровни требуют понижения и получают обратную связь от понижений посредством обратного вызова.
Q2. При принятии некоторых мер предосторожности они не хуже, чем, например, исключения. В некотором смысле, они похожи.
Q3. Больше сочетаний: более низкие значки знают выше.
Примечание:
- простой способ (1 обработчик обратного вызова для обратного вызова): Регистрация объектов CallbackHandler через интерфейсы
- Используйте сигналы (QT, boost,...) и убедитесь, что для обратного вызова используются уникальные сигналы для улучшения отслеживания.
Изменить: пример:
Пользователь вызывает протокол ProtocolHandler для отправки сообщения, а ProtocolHandler вызывает пользователя для отправки ответа: взаимная зависимость.
Layered: пользователь более высокий уровень, ProtocolHandler - более низкий уровень. При запуске он регистрирует обратный вызов для ответа и вызывает протокол ProtocolHandler для отправки сообщения. ПротоколHandler использует обратный вызов для отправки ответа: только пользователь зависит от протоколаHandler.
Ответ 7
Если мы в контексте С++ рассмотрим (например, обобщенные обратные вызовы).
Основная идея заключается в том, что callback (метод класса) может быть любого имени, и обратный вызов не требуется для получения какого-либо класса, известного исполнителем обратного вызова.
Единственным ограничением для обратного вызова являются входные аргументы и возвращаемое значение. Таким образом, это уменьшает пару до нуля...:)
UDP:
Ответа на этот вопрос @EffoStaff Effo является примером, когда обратный вызов должен быть определенного класса (получение) и иметь имя исправления. Все эти "ограничения" отсутствуют в контексте обобщения обратных вызовов.
Ответ 8
В редких сценариях с обратными вызовами в стиле Win32 не учитывайте проблемы "неясного повторного входа" (следующее обращение не имеет значения, если по обратному вызову вы просто означаете очень базовую передачу функции как аргумент другой функции, где проблемы concurrency немыслимы).
Отличный индекс для Джо Даффи "Параллельное программирование в Windows" содержит 5 тем под "повторной установкой", которые обычно являются специализациями концепции "Вокруг Робин-Худ-Амбар-РЕЗЕРВИРОВАНИЕ НА ИГРУШУЮ РЕЗЬЮ" - другими словами, из лучших -answer "вызываемая сторона передается некоторым указателем, и она понятия не имеет, что за ней". "Не знаю" иногда может привести к тому, что вокруг-Робин-Худ-сарай.
Ничто из того, что я только что сказал, не относится к обратным вызовам, но если вызываемая сторона натыкается на один из сценариев Даффи, то может произойти "неясное повторное включение". Другими словами, подразумеваемая концепция "обратного вызова" заключается в том, что вы, как представляется, вызываете обратно в одном потоке, как это происходит, как он синхронизируется.
Если вы используете Google в названии книги Duffy и переместите слово Callback на свой поиск, вы получите более 10 страниц хитов.