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

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

24.07.2017, 20:56. Показов 1313. Ответов 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
Ответ Создать тему
Новые блоги и статьи
Советы по крайней бережливости. Внимание, это ОЧЕНЬ длинный пост.
Programma_Boinc 28.12.2025
Советы по крайней бережливости. Внимание, это ОЧЕНЬ длинный пост. Налог на собак: https:/ / **********/ gallery/ V06K53e Финансовый отчет в Excel: https:/ / **********/ gallery/ bKBkQFf Пост отсюда. . .
Кто-нибудь знает, где можно бесплатно получить настольный компьютер или ноутбук? США.
Programma_Boinc 26.12.2025
Нашел на реддите интересную статью под названием Anyone know where to get a free Desktop or Laptop? Ниже её машинный перевод. После долгих разбирательств я наконец-то вернула себе. . .
Thinkpad X220 Tablet — это лучший бюджетный ноутбук для учёбы, точка.
Programma_Boinc 23.12.2025
Рецензия / Мнение/ Перевод Нашел на реддите интересную статью под названием The Thinkpad X220 Tablet is the best budget school laptop period . Ниже её машинный перевод. Thinkpad X220 Tablet —. . .
PhpStorm 2025.3: WSL Terminal всегда стартует в ~
and_y87 14.12.2025
PhpStorm 2025. 3: WSL Terminal всегда стартует в ~ (home), игнорируя директорию проекта Симптом: После обновления до PhpStorm 2025. 3 встроенный терминал WSL открывается в домашней директории. . .
Как объединить две одинаковые БД Access с разными данными
VikBal 11.12.2025
Помогите пожалуйста !! Как объединить 2 одинаковые БД Access с разными данными.
Новый ноутбук
volvo 07.12.2025
Всем привет. По скидке в "черную пятницу" взял себе новый ноутбук Lenovo ThinkBook 16 G7 на Амазоне: Ryzen 5 7533HS 64 Gb DDR5 1Tb NVMe 16" Full HD Display Win11 Pro
Музыка, написанная Искусственным Интеллектом
volvo 04.12.2025
Всем привет. Некоторое время назад меня заинтересовало, что уже умеет ИИ в плане написания музыки для песен, и, собственно, исполнения этих самых песен. Стихов у нас много, уже вышли 4 книги, еще 3. . .
От async/await к виртуальным потокам в Python
IndentationError 23.11.2025
Армин Ронахер поставил под сомнение async/ await. Создатель Flask заявляет: цветные функции - провал, виртуальные потоки - решение. Не threading-динозавры, а новое поколение лёгких потоков. Откат?. . .
Поиск "дружественных имён" СОМ портов
Argus19 22.11.2025
Поиск "дружественных имён" СОМ портов На странице: https:/ / norseev. ru/ 2018/ 01/ 04/ comportlist_windows/ нашёл схожую тему. Там приведён код на С++, который показывает только имена СОМ портов, типа,. . .
Сколько Государство потратило денег на меня, обеспечивая инсулином.
Programma_Boinc 20.11.2025
Сколько Государство потратило денег на меня, обеспечивая инсулином. Вот решила сделать интересный приблизительный подсчет, сколько государство потратило на меня денег на покупку инсулинов. . . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2025, CyberForum.ru