Форум программистов, компьютерный форум, киберфорум
Наши страницы
С++ для начинающих
Войти
Регистрация
Восстановить пароль
 
 
Рейтинг 4.50/6: Рейтинг темы: голосов - 6, средняя оценка - 4.50
diplomat1129
0 / 0 / 0
Регистрация: 11.02.2013
Сообщений: 83
1

Заменить делегаты функциями обратного вызова

14.04.2014, 14:48. Просмотров 1121. Ответов 26
Метки нет (Все метки)

C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
 public event EventHandler<EventClientArgs> OnNewClient;
        /// <summary>
        /// Обработка добавления нового клиента - процедура синхронизируется с потоком Control и вызывается событие
        /// </summary>
        /// <param name="Id">Адрес клиента</param>
        /// <param name="Name">Имя клиента</param>
        private void NewClientEvent(int Id, string Name)
        {
            /*if ((Control != null) && Control.InvokeRequired)
            {
                DelegateChangeClientEvent Ev = new DelegateChangeClientEvent(NewClientEvent);
                Control.Invoke(Ev, Id, Name);
            }
            else*/
                if (OnNewClient != null)
                    OnNewClient(this, new EventClientArgs(Id, Name));
        }
Мне надо сделать аналог на с++. с делегатами разобрался - их надо заменить функциями обратного вызова..
а вот как быть с событиями. есть ли аналог?или как то же обходятся люди ?
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
14.04.2014, 14:48
Ответы с готовыми решениями:

Функция обратного вызова
#undef UNICODE #include &lt;windows.h&gt; #include &quot;resource.h&quot; #include...

Стрелка в описании функции обратного вызова
#include &lt;iostream&gt; #include &lt;algorithm&gt; std::string s = &quot;hello&quot;; auto end =...

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

нужно чтобы функция располагалась до ее вызова, после ее вызова и в другом файле. Как это сделать?
#include &lt;iostream&gt; #include &lt;conio.h&gt; using namespace std; int n, *c; ...

оформить решение в виде функции следующими способами: 1. функция расположена после ее вызова; 2. функция расположена после до ее вызова; 3. функ
оформить решение в виде функции следующими способами: 1. функция расположена...

26
AceOfSpades
48 / 47 / 5
Регистрация: 14.08.2012
Сообщений: 248
14.04.2014, 20:13 2
Лучший ответ Сообщение было отмечено diplomat1129 как решение

Решение

Делается довольно несложно. Проект прилагаю.
Класс EventHandler реализует работу по подписке/отписке и вызову обработчиков события. Весь остальной код, предполагается, что пишет пользователь, и использует "библиотечный" EventHandler для определения своих событий.
Единственное ограничение: обработчики событий должны быть определены вне класса (а если им требуется доступ к внутренностям класса, то просто объявить их друзьями). Хотя, ничего плохого в этом не вижу, наоборот, код структурируется.
1
Вложения
Тип файла: 7z Test.7z (2.1 Кб, 12 просмотров)
diplomat1129
0 / 0 / 0
Регистрация: 11.02.2013
Сообщений: 83
17.04.2014, 19:22  [ТС] 3
Ошибка почему-то.когда использую ваш заголовочный файл
0
AceOfSpades
48 / 47 / 5
Регистрация: 14.08.2012
Сообщений: 248
17.04.2014, 19:25 4
Какая?
0
diplomat1129
0 / 0 / 0
Регистрация: 11.02.2013
Сообщений: 83
17.04.2014, 19:32  [ТС] 5
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
In file included from NMClient.cpp:14:0,
                 from main.cpp:1:
EventHandler.h: In member function ‘void EventHandler<EventArgs>::operator()(void*, EventArgs*):
EventHandler.h:34:8: error: need ‘typename’ before ‘std::list<void (*)(void*, EventArgs*)>::const_iterator’ because ‘std::list<void (*)(void*, EventArgs*)>’ is a dependent scope
   for (list<CallBackFunction>::const_iterator it = callBackList.cbegin(); it != callBackList.cend(); it++)
        ^
EventHandler.h:34:47: error: expected ‘;’ before ‘it’
   for (list<CallBackFunction>::const_iterator it = callBackList.cbegin(); it != callBackList.cend(); it++)
                                               ^
EventHandler.h:34:75: error: ‘it’ was not declared in this scope
   for (list<CallBackFunction>::const_iterator it = callBackList.cbegin(); it != callBackList.cend(); it++)
                                                                           ^
EventHandler.h: In member function ‘bool EventHandler<EventArgs>::operator==(int):
EventHandler.h:38:47: warning: NULL used in arithmetic [-Wpointer-arith]
  inline bool operator==(int a) { return (a == NULL) && (callBackList.size() == 0); }
                                               ^
EventHandler.h: In member function ‘bool EventHandler<EventArgs>::operator!=(int):
EventHandler.h:40:47: warning: NULL used in arithmetic [-Wpointer-arith]
  inline bool operator!=(int a) { return (a == NULL) && (callBackList.size() != 0); }
0
DrOffset
8137 / 4719 / 1153
Регистрация: 30.01.2014
Сообщений: 7,690
17.04.2014, 19:42 6
Лучший ответ Сообщение было отмечено diplomat1129 как решение

Решение

diplomat1129,
Там ошибка. Связанная с тем, что VC++ не требует наличия ключевого слова typename в этой ситуации (это объясняется отсутствием в VC++ two-phase name lookup, но это тянет на отдельную тему), хотя по стандарту оно должно быть.
В общем, надо так:
C++
1
for (typename list<CallBackFunction>::const_iterator it = callBackList.cbegin(); it != callBackList.cend(); it++)
1
diplomat1129
0 / 0 / 0
Регистрация: 11.02.2013
Сообщений: 83
17.04.2014, 19:46  [ТС] 7
C++
1
2
3
4
5
6
7
8
9
In file included from NMClient.cpp:14:0,
                 from main.cpp:1:
EventHandler.h: In member function ‘bool EventHandler<EventArgs>::operator==(int):
EventHandler.h:38:47: warning: NULL used in arithmetic [-Wpointer-arith]
  inline bool operator==(int a) { return (a == NULL) && (callBackList.size() == 0); }
                                               ^
EventHandler.h: In member function ‘bool EventHandler<EventArgs>::operator!=(int):
EventHandler.h:40:47: warning: NULL used in arithmetic [-Wpointer-arith]
  inline bool operator!=(int a) { return (a == NULL) && (callBackList.size() != 0); }
0
DrOffset
8137 / 4719 / 1153
Регистрация: 30.01.2014
Сообщений: 7,690
17.04.2014, 19:48 8
diplomat1129, Насчет этого наверное лучше у автора спросить. Но мне кажется, что можно просто заменить на ноль.
1
diplomat1129
0 / 0 / 0
Регистрация: 11.02.2013
Сообщений: 83
17.04.2014, 20:13  [ТС] 9
Начал использовать события
C++
1
2
3
4
5
6
EventHandler<EventMsgArgs> OnError;
 
    void ErrorEvent(string msg){
        if (OnError != 0)
          OnError(this, new EventMsgArgs(msg));
    }
Выдает такое
In file included from NMClient.cpp:14:0,
from main.cpp:1:
EventHandler.h: In instantiation of ‘void EventHandler<EventArgs>::operator()(void*, EventArgs*) [with EventArgs = EventMsgArgs]’:
NMClient.cpp:50:40: required from here
EventHandler.h:34:81: error: ‘class std::list<void (*)(void*, EventMsgArgs*), std::allocator<void (*)(void*, EventMsgArgs*)> >’ has no member named ‘cbegin’
for (typename list<CallBackFunction>::const_iterator it = callBackList.cbegin(); it != callBackList.cend(); it++)
^
EventHandler.h:34:87: error: ‘class std::list<void (*)(void*, EventMsgArgs*), std::allocator<void (*)(void*, EventMsgArgs*)> >’ has no member named ‘cend’
for (typename list<CallBackFunction>::const_iterator it = callBackList.cbegin(); it != callBackList.cend(); it++)

если не использовать в другом классе, а просто компилить, то компилиться без ошибок
0
DrOffset
8137 / 4719 / 1153
Регистрация: 30.01.2014
Сообщений: 7,690
17.04.2014, 20:18 10
diplomat1129, C++11 нужно, чтобы это работало. -std=c++11
0
AceOfSpades
48 / 47 / 5
Регистрация: 14.08.2012
Сообщений: 248
17.04.2014, 22:41 11
Всё это возможно из-за того, что я не учитывал особенности VC++ и C++11, т.к. первый категорически не перевариваю (из-за личных взглядов), а для второго у меня нет поддержки компилятора.
Изначально я создавал проект для этого файла как обычный Win32 без всяких там .net и clr. Среда разработки VS2010.
По поводу этих ошибок сказать трудно, что компилятору не нравится, может нет нужных зависимостей, иначе почему он ругается на отсутствие вполне стандартного члена библиотеки.
0
DrOffset
8137 / 4719 / 1153
Регистрация: 30.01.2014
Сообщений: 7,690
17.04.2014, 22:49 12
Цитата Сообщение от AceOfSpades Посмотреть сообщение
По поводу этих ошибок сказать трудно, что компилятору не нравится, может нет нужных зависимостей, иначе почему он ругается на отсутствие вполне стандартного члена библиотеки.
Этот метод появился только в С++11. Возможно в VS2010 уже были реализованы некоторые фичи заранее.
Автор, ИМХО, собирает проект в каком-то GCC.
Ключевое слово typename не обязательно в той ситуации в VS2010 (как и в любой другой студии) исходя из отсутствия реализации в компиляторе two-phase name lookup. Некоторые считают, что это хорошо, однако подобный код все-таки остается нестандартным. И GCC вполне обоснованно его не собирает.
0
AceOfSpades
48 / 47 / 5
Регистрация: 14.08.2012
Сообщений: 248
17.04.2014, 23:21 13
Цитата Сообщение от DrOffset Посмотреть сообщение
однако подобный код все-таки остается нестандартным. И GCC вполне обоснованно его не собирает.
Возможно. В таком случае нужно сделать код более "стандартным".
0
DrOffset
8137 / 4719 / 1153
Регистрация: 30.01.2014
Сообщений: 7,690
17.04.2014, 23:36 14
AceOfSpades, выше я уже показывал как
1
diplomat1129
0 / 0 / 0
Регистрация: 11.02.2013
Сообщений: 83
18.04.2014, 10:05  [ТС] 15
События сделал. ВОт например
C++
1
2
3
4
5
6
EventHandler<EventArgs> OnStop;
 
    void StopEvent(){
        if (OnStop != 0)
            OnStop(this, new EventArgs());
    }
В классе NMclient
в main
C++
1
2
3
4
5
6
7
void MyMeth1(void* obj, ClientEventArgs* args){
    
}
int main(){
    NMClient* client = new NMClient("127.0.0.1", 9000);
    client->OnStop += MyMeth1;
}
Выдает

main.cpp:5:25: error: ‘ClientEventArgs’ has not been declared
In file included from main.cpp:1:0:
NMClient.cpp: In function ‘int main()’:
NMClient.cpp:67:26: error: ‘EventHandler<EventArgs> NMClient::OnStop’ is private
main.cpp:10:10: error: within this context
main.cpp:10:20: error: invalid conversion from ‘void (*)(void*, int*)’ to ‘EventHandler<EventArgs>::CallBackFunction {aka void (*)(void*, EventArgs*)}’ [-fpermissive]
In file included from NMClient.cpp:14:0,
from main.cpp:1:
EventHandler.h:18:30: error: initializing argument 1 of ‘EventHandler<EventArgs>& EventHandler<EventArgs>::operator+=(EventHandler<EventArgs>::CallBackFunction) [with EventArgs = EventArgs; EventHandler<EventArgs> = EventHandler<EventArgs>; EventHandler<EventArgs>::CallBackFunction = void (*)(void*, EventArgs*)]’ [-fpermissive]
0
AceOfSpades
48 / 47 / 5
Регистрация: 14.08.2012
Сообщений: 248
18.04.2014, 10:22 16
Типы параметров не совпадают. В вашем методе тип ClientEventArgs, а в классе определен хэндлер с типом EventArgs. Либо приводите тип, либо хэндлер объявите тоже с типом ClientEventArgs.
И ошибки:
ClientEventArgs - не объявлен (может инклуд забыли?)
OnStop - объявите публичным, иначе он не виден снаружи класса

Добавлено через 11 минут
Правила создания событий лучше делать такие:
Имя события - что-то случилось, в вашем случае Stopped.
Метод, вызывающий событие - защищенный виртуальный с приставкой On, в вашем случае
protected: virtual void OnStopped();
И всё-таки не с нулем лучше сравнивать, а с NULL (null), если он у вас не определен, то добавьте перед описанием класса #define null 0
Это общепринятый стиль в C#, раз уж вы его в С++ решили перетащить.
1
DrOffset
8137 / 4719 / 1153
Регистрация: 30.01.2014
Сообщений: 7,690
18.04.2014, 15:05 17
Цитата Сообщение от AceOfSpades Посмотреть сообщение
И всё-таки не с нулем лучше сравнивать, а с NULL (null), если он у вас не определен, то добавьте перед описанием класса #define null 0
Все-таки лучше так не делать. NULL определен, но он используется для указателей, а в современном языке его лучше вообще не использовать, вместо него уже есть стандартный nullptr. Если очень хочется именно null, то лучше константу объявить.
C++
1
static const int null = 0;
0
AceOfSpades
48 / 47 / 5
Регистрация: 14.08.2012
Сообщений: 248
18.04.2014, 16:19 18
Цитата Сообщение от DrOffset Посмотреть сообщение
NULL определен, но он используется для указателей
Речь же шла о подобии в C#, а там все ссылочные типы (классы и указатели) могут быть null.
static const int null = 0; - если больше нигде не нужно использовать null в других файлах, то можно.

Чем #define хуже? Мы же определяем новую семантику для типа, а не переменную.
0
DrOffset
8137 / 4719 / 1153
Регистрация: 30.01.2014
Сообщений: 7,690
18.04.2014, 16:50 19
Цитата Сообщение от AceOfSpades Посмотреть сообщение
Речь же шла о подобии в C#
Речь шла о портировании на С++, а это разные вещи. В каждом языке есть свои нюансы, и их надо учитывать. Вслепую копировать подходы из одного языка в другой - неправильно.
Цитата Сообщение от AceOfSpades Посмотреть сообщение
а там все ссылочные типы (классы и указатели) могут быть null.
Вот в этом коде нет ссылочных типов. И здесь мы сравниваем значение а с NULL, а не ссылку на а с NULL. Поэтому, если не имелось в виду сравнение с нулем, то в С++ этот код бессмысленный.
C++
1
inline bool operator==(int a) { return (a == NULL) && (callBackList.size() == 0); }
Цитата Сообщение от AceOfSpades Посмотреть сообщение
Чем #define хуже?
Тем, что это макроподстановка. Отдельный язык по сути, с С++ он никак не связан и система типов С++ не сможет проконтролировать операции с ним. Это просто замена в тексте.
Цитата Сообщение от AceOfSpades Посмотреть сообщение
Мы же определяем новую семантику для типа, а не переменную.
Препроцессор ничего не знает про типы. Это такая автоматизированная автозамена.
0
AceOfSpades
48 / 47 / 5
Регистрация: 14.08.2012
Сообщений: 248
18.04.2014, 17:34 20
Цитата Сообщение от DrOffset Посмотреть сообщение
Препроцессор ничего не знает про типы. Это такая автоматизированная автозамена.
При чём тут препроцессор? Это его проблемы, что он не знает про типы, но человек же знает. Поэтому макроподстановки и полезны, делают язык более гибким.
Выражение OnStop != 0 для меня, например означает, что OnStop имеет семантику значения (хотя в данном случае это не так), что вызывает дискомфорт или даже путаницу (почему бы тогда не сравнивать с 1, 2 ...).
Выражение OnStop != null (уже ясно дает понять, что речь идет прежде всего о типе (неважно, указатель это или что-то другое). Хотя формальной разницы тут нет. Объявление null как константы опять же вносит семантику значения...
В общем не буду больше с вами спорить.
0
18.04.2014, 17:34
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
18.04.2014, 17:34

Делегаты и события
Всем доброго времени суток. Понадобилось код из C# переделать на C++. Кода в...

Собираются ли вводить делегаты?
или так и собираются строго придерживаться тому, что есть - писать уже с...

Почему callback-функции называются функциями ОБРАТНОГО вызова
Доброго времени. Нуждаюсь в объяснении. Очередной вопрос в стиле «Что такое...


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

Или воспользуйтесь поиском по форуму:
20
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2018, vBulletin Solutions, Inc.
Рейтинг@Mail.ru