Форум программистов, компьютерный форум, киберфорум
C++
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 5.00/6: Рейтинг темы: голосов - 6, средняя оценка - 5.00
 Аватар для Arcor
5709 / 2300 / 466
Регистрация: 20.11.2009
Сообщений: 7,721
Записей в блоге: 1

Callback. Так ли используется на практике?

24.07.2017, 20:56. Показов 1339. Ответов 9
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Доброго времени суток.

Сам по большему счету я работаю с Delphi, но тут сложилась надобность в С/С++ состряпать механизм "событий", как это привычно называется в Delphi или функций обратного вызова. Чутку покумекав, пришел к такому выводу, что сие можно организовать через указатель на функцию в С/С++ и в общем-то состряпал, все работает как и ожидалось. Вот код ниже должен это демонстрировать, пример на абум, отсюда и вопрос, корректно ли так использовать данный механизм? Или что-то однажды окажется "подводным камнем"?

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
#include <iostream>
 
using namespace std;
 
// Тип-Указатель на некую функцию
typedef void(*ClbFunc)(int, int);
 
// Некая функция, которая дожна быть вызвана
void TestFunc(int a, int b)
{
    cout << "Func is called!" << endl; 
    cout << a  << " + " << b << " = " << a + b << endl << endl;
}
 
// Некий класс, который будет генерировать "событие", 
// чтобы вызвать некую функцию извне
class TestCallback
{
public:
    TestCallback();
    void CallTheFunc(int a, int b);
    void SetCallBack(ClbFunc a);
private:
    // указатель на функцуию, которым будем оперировать внутри класса
    ClbFunc func;
};
 
TestCallback::TestCallback()
{
    func = NULL;
}
 
void TestCallback::SetCallBack(ClbFunc a)
{
    func = a;
}
 
void TestCallback::CallTheFunc(int a, int b)
{
    if (func != NULL && a == b)
        func(a, b); 
}
 
int main()
{
    TestCallback *t = new TestCallback;
 
    t->SetCallBack(TestFunc);
 
    t->CallTheFunc(10, 12);
    t->CallTheFunc(20, 20);
    t->CallTheFunc(50, 43);
    t->CallTheFunc(7, 7);
    t->CallTheFunc(12, 2485);
 
    system("pause");
    return 0;
}
Миниатюры
Callback. Так ли используется на практике?  
0
Programming
Эксперт
39485 / 9562 / 3019
Регистрация: 12.04.2006
Сообщений: 41,671
Блог
24.07.2017, 20:56
Ответы с готовыми решениями:

Для чего на практике используется XML в Web-программировании?
Пишу уже два года сайты на ASP. Хочу вот начать осваивать XML-технологии, так как сейчас это вроде как модно везде где можно XML втыкнуть...

Где используется AES шифрование на практике, в каких информационных системах
Доброго времени суток. Интересует следующее: где используется AES шифрование на практике, в каких информационных системах, для чего?...

For_each и аргументы callback-функции; Как передать callback'у больше одного аргумента
Изучаю контейнеры и алгоритмы stl по Майерсу . С непривычки слегка охренел и запутался в них . В общем есть у меня простой вызов...

9
Каждому свое
 Аватар для Bretbas
533 / 219 / 81
Регистрация: 05.08.2013
Сообщений: 1,614
27.07.2017, 21:41
Я что-то в твоем коде не вижу событий. Ты же хочешь систему событий, я так понимаю? И хендлеры подписанные на то или иное событие.
У тебя вижу в коде только передачу функции по указателю в класс, и делегированный вызов этой функции...
1
 Аватар для Arcor
5709 / 2300 / 466
Регистрация: 20.11.2009
Сообщений: 7,721
Записей в блоге: 1
29.07.2017, 19:37  [ТС]
Да это был первый тест, чтобы вызвать функцию "неявно" и то, я не знаю так ли это правильно делается, но по примеру выше, я получил нужный мне результат. Мне нужно, чтобы при определенных обстоятельствах, вызывалась некая функция, первым, что пришло в голову, вызвать по указателю некую функцию внутри какого-то класса, в котором происходят какие-то вещи, а в функции "снаружи" уже забираю нужный мне результат. Пример конечно же не ахти, но получил же обратную реакцию функции. На реальном примере, все конечно же будет запакованно в классы и явный такой вот вызов, как из примера
C++
1
2
3
4
5
t->CallTheFunc(10, 12);
t->CallTheFunc(20, 20);
t->CallTheFunc(50, 43);
t->CallTheFunc(7, 7);
t->CallTheFunc(12, 2485);
конечно снаружи не будет, это будет в механизме внутрененго мира некого класса

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

а по ответам и их сожержанию, могу судить, что нет претензий к тому, что спрашиваю и сделал все как-то так, ну или вообще все не так, что уж лучше об этом не говорить?

ладно.. попробую так пока что)
0
Каждому свое
 Аватар для Bretbas
533 / 219 / 81
Регистрация: 05.08.2013
Сообщений: 1,614
30.07.2017, 08:16
Arcor, Вот простейшая сырая система событий:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
#include <iostream>
#include <vector>
#include <string>
#include <map>
#include <algorithm>
 
class EventSystem
{
public:
    typedef void(*fun)();    
    
    inline void subscribeEvent( const std :: string eventName, fun f )
    {
        auto event = _events.find( eventName );
        if( event != _events.end() )
            event -> second.push_back( f );
        else
        {
            std :: vector<fun> v;
            v.push_back( f );
            _events.insert( std :: pair<std :: string, std :: vector<fun>>( eventName, v ) );
        }
    }
    
    inline void unsubscribeEvent( const std :: string eventName, fun f )
    {
        auto event = _events.find( eventName );
        if( event != _events.end() )
        {
            auto handler = std :: find( event -> second.begin(), event -> second.end(), f );
            event -> second.erase( handler );
        }
    }
    
    inline void invokeEvent( const std :: string eventName )
    {
        auto event = _events.find( eventName );
        if( event != _events.end() )  
        {
            for( const auto& f : event -> second )
                f();
        }
    }
    
private:
    std :: map<std :: string, std :: vector<fun>> _events;
};
 
 
void fun1()
{
    std :: cout << "Invoked fun1" << std :: endl;
}
void fun2()
{
    std :: cout << "Invoked fun2" << std :: endl;
}
void fun3()
{
    std :: cout << "Invoked fun3" << std :: endl;
}
void fun4()
{
    std :: cout << "Invoked fun4" << std :: endl;
}
void fun5()
{
    std :: cout << "Invoked fun5" << std :: endl;
}
void fun6()
{
    std :: cout << "Invoked fun6" << std :: endl;
}
 
int main()
{
    EventSystem eventSystem;
    
    // Подписываем два хендлера на событие Event1
    eventSystem.subscribeEvent( "Event1", fun1 );
    eventSystem.subscribeEvent( "Event1", fun2 );
    
    // Подписываем два хендлера на событие Event2
    eventSystem.subscribeEvent( "Event2", fun3 );
    eventSystem.subscribeEvent( "Event2", fun4 );
    
    // Подписываем два хендлера на событие Event3
    eventSystem.subscribeEvent( "Event3", fun5 );
    eventSystem.subscribeEvent( "Event3", fun6 );   
    
    eventSystem.invokeEvent( "Event2" );                // Вызываем событие Event2
    eventSystem.unsubscribeEvent( "Event2", fun4 );     // Отписываем хендлер от события Event2
    eventSystem.invokeEvent( "Event2" );                // Снова вызываем Event2
    
    eventSystem.invokeEvent( "Event1" );                // Вызываем событие Event1
    
    eventSystem.invokeEvent( "Event3" );                // Вызываем событие Event3  
}
Написал на коленях так сказать...кури пока ее.
Как поймешь, начни разбираться:
1. как сделать события не std::string, тоесть чтобы они хранились не в строках. У меня к примеру в реализации системы событий за счет определенного макроса генерируется макрос, который автоматом задает имя структуры и тип хендлера, который можно подписать на это событие
2. В моем приведенном коде, хендлер не имел параметров вовсе. Это не есть хорошо. Нужно сделать, чтобы ты создавал события, которые могли подписывать на себя разные прототипы хендлеров - событие 1: void(*)(int); событие 2: void(*)(); событие 3: void(*)(int, std :: string, float) и тд. Но вызов того или иного события все равно происходил через метод invoke(...) класса EventSystem. Чтобы такого достичь, читай про "Шаблоны с переменным числом параметров" или variadic templates
1
 Аватар для Arcor
5709 / 2300 / 466
Регистрация: 20.11.2009
Сообщений: 7,721
Записей в блоге: 1
31.07.2017, 00:05  [ТС]
Ну и? Смысл сводится к тому, это то же самое, что и я и написал выше, только я более скудный пример описал, может я не вижу главного различия, но работает по той же системе.

Смысл все таки сводится к тому, что вызывается функция по указателю и больше ничего иного там не производится. Все ясно. Всем спасибо

Пункт 2 в тексте не ясен, для чего мне "подписывать" одним методом все различные события? Понятное дело, что со списком (вектором) через цикл можно пробегаться и исктаь там что надо и уже ветвить трали-вали, НО, не более ли логичнее сказать - я хочу использовать событие "А", описать его как надо для "А" и установить все необходимое для "А" и будет явное "А".
Надо второе событие "Б", описать под "Б" все, но с другим списком аргументов. И потом просто коннектить/дисконнектить те события, которые я хочу использовать вообще. И не понятно для чего вообще делать чтобы от одного условия выполнялись несколько событий, ну ОК, пусть, но осуществится то просто точно так же)))

НО, спорить с профессионалами конечно же не стану ...

Не по теме:

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

0
 Аватар для RunningMan
278 / 186 / 75
Регистрация: 12.04.2017
Сообщений: 1,088
Записей в блоге: 2
31.07.2017, 01:35
Цитата Сообщение от Arcor Посмотреть сообщение
Смысл все таки сводится к тому, что вызывается функция по указателю и больше ничего иного там не производится.
У вас у обоих так и есть.
Цитата Сообщение от Arcor Посмотреть сообщение
состряпать механизм "событий"
паттерн наблюдатель

Наблюдатель (шаблон проектирования)
1
Ушел с форума
Эксперт С++
 Аватар для Убежденный
16481 / 7444 / 1187
Регистрация: 02.05.2013
Сообщений: 11,616
Записей в блоге: 1
31.07.2017, 10:18
Цитата Сообщение от Arcor Посмотреть сообщение
корректно ли так использовать данный механизм? Или что-то однажды окажется "подводным камнем"?
Я бы посоветовал добавить сюда две вещи:

1. У callback-функции и ее прототипа четко определить соглашение о вызовах - stdcall, cdecl, fastcall и т.д.
Это поможет в будущем избежать различных ошибок при внесении изменений в программу.

2. Дать возможность клиенту передавать в callback какие-то свои данные.
Обычно это делается через дополнительный параметр размером sizeof (void *).

Пример:
C++
1
2
// Тип-Указатель на некую функцию
typedef void(_stdcall * ClbFunc)(int, int, void *);

Не по теме:


Цитата Сообщение от Arcor Посмотреть сообщение
да и "ты", как-то не очень чужих и незнакомых людей ТЫкать
"Ты" на форумах не является признаком неуважения или чего-то такого "неприличного".

2
Каждому свое
 Аватар для Bretbas
533 / 219 / 81
Регистрация: 05.08.2013
Сообщений: 1,614
01.08.2017, 08:14
Arcor,
Цитата Сообщение от Arcor Посмотреть сообщение
Смысл сводится к тому, это то же самое, что и я и написал выше, только я более скудный пример описал, может я не вижу главного различия, но работает по той же системе.
Ты хотел сделать систему событий, в твоем коде я события не нашел вовсе. Поэтому различия все-таки есть. А то, что вызов функции по указателю у нас с тобой проходит одинаково, это еще не значит что смысл сводится к одному и тому же

Цитата Сообщение от Arcor Посмотреть сообщение
Пункт 2 в тексте не ясен, для чего мне "подписывать" одним методом все различные события? Понятное дело, что со списком (вектором) через цикл можно пробегаться и исктаь там что надо и уже ветвить трали-вали, НО, не более ли логичнее сказать - я хочу использовать событие "А", описать его как надо для "А" и установить все необходимое для "А" и будет явное "А".
Надо второе событие "Б", описать под "Б" все, но с другим списком аргументов. И потом просто коннектить/дисконнектить те события, которые я хочу использовать вообще. И не понятно для чего вообще делать чтобы от одного условия выполнялись несколько событий, ну ОК, пусть, но осуществится то просто точно так же)))
Я это и имел ввиду, наверное просто плохо написал. У каждого события свой тип прототипа хендлеров, но никак не разные.

RunningMan,
Цитата Сообщение от RunningMan Посмотреть сообщение
паттерн наблюдатель
Я не соглашусь...паттерн наблюдатель и паттерн система событий похожи, не спорю. Но есть разница.
Также как и паттерн система сообщений и паттерн система событий, тоже очень похожи, но тоже имеют разницу.
Если нужно, я найду линки, где можно почитать об этом подробнее

Убежденный,
Цитата Сообщение от Убежденный Посмотреть сообщение
Дать возможность клиенту передавать в callback какие-то свои данные.
Обычно это делается через дополнительный параметр размером sizeof (void *).
Ну сейчас на помощь пришли variadic templates. И можно хитро сделать так, чтобы при вызове к примеру:
eventSystem -> invoke<SOME_EVENT>( параметры для SOME_EVENT )
параметры метода invoke изменялись в зависимости от переданного шаблонного параметра.
1
 Аватар для Arcor
5709 / 2300 / 466
Регистрация: 20.11.2009
Сообщений: 7,721
Записей в блоге: 1
01.08.2017, 11:05  [ТС]
Я все понимаю, ребят, у меня опыта просто нету Когда-то он появится возможно и появятся уже совсем другие слова и значения в обиходе и конечно же опыт))) Но с чего-то начать надо было

Благодарю всех за содействие!
0
Каждому свое
 Аватар для Bretbas
533 / 219 / 81
Регистрация: 05.08.2013
Сообщений: 1,614
01.08.2017, 13:06
Arcor,
Цитата Сообщение от Arcor Посмотреть сообщение
НО, спорить с профессионалами конечно же не стану ...
Да, и я не профессионал...хотя очень хочу им стать...я порой смотрю здесь на форуме на просто демонов c++ каких-то, и у меня сразу руки опускаются...просто в мыслях после только одно: как можно столько знать? Это нереально...

Я учусь сам, и очень часто задаю тупые вопросы
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
inter-admin
Эксперт
29715 / 6470 / 2152
Регистрация: 06.03.2009
Сообщений: 28,500
Блог
01.08.2017, 13:06
Помогаю со студенческими работами здесь

Невозможно получить доступ к файлу так как он используется другим процессом
Есть файл .jpg он формируется функцией bmp-&gt;save(pathToFile). После этого используется функция picturebox-&gt;Load(pathToFile). А после...

Не удалось получить доступ к файлу так как он используется другим процессом
Здраствуйте вознилка роблема не удалось получить доступ к файлу так как этот файл используется другим процессом в чём судь я хочу сделать...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
10
Ответ Создать тему
Новые блоги и статьи
Midnight Chicago Blues
kumehtar 24.03.2026
Такой Midnight Chicago Blues, знаешь?. . Когда вечерние улицы становятся ночными, а ты не можешь уснуть. Ты идёшь в любимый старый бар, и бармен наливает тебе виски. Ты смотришь на пролетающие. . .
Контроль уникальности заводского номера - вариант №2
Maks 24.03.2026
В отличие от предыдущего варианта добавлено прерывание циклов, также добавлены новые переменные для сохранения контекста ошибки перед прерыванием цикла: Процедура ПередЗаписью(Отказ, РежимЗаписи,. . .
SDL3 для Desktop (MinGW): Вывод текста со шрифтом TTF с помощью библиотеки SDL3_ttf на Си и C++
8Observer8 24.03.2026
Содержание блога Финальные проекты на Си и на C++: finish-text-sdl3-c. zip finish-text-sdl3-cpp. zip
Жизнь в неопределённости
kumehtar 23.03.2026
Жизнь — это постоянное существование в неопределённости. Например, даже если у тебя есть список дел, невозможно дойти до точки, где всё окончательно завершено и больше ничего не осталось. В принципе,. . .
Модель здравоСохранения: работники работают быстрее после её введения.
anaschu 23.03.2026
geJalZw1fLo Корпорация до введения программа здравоохранения имела много невыполненных работниками заданий, после введения программы количество заданий выросло. Но на выплатах по больничным это. . .
Контроль уникальности заводского номера - вариант №1
Maks 23.03.2026
Алгоритм контроля уникальности заводского (или серийного) номера на примере документа выдачи шин для спецтехники с табличной частью в КА2. Данные берутся из регистра сведений, по которому настроено. . .
Хочу заставить корпорации вкладываться в здоровье сотрудников: делаю мат модель здравосохранения
anaschu 22.03.2026
e7EYtONaj8Y Z4Tv2zpXVVo https:/ / github. com/ shumilovas/ med2. git
Программный отбор элементов справочника по группе
Maks 22.03.2026
Установка программного отбора элементов справочника "Номенклатура" из модуля формы документа в КА2. В качестве фильтра для отбора справочника служит группа номенклатуры. Отбор по наименованию. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru