Форум программистов, компьютерный форум CyberForum.ru

C++

Войти
Регистрация
Восстановить пароль
 
Рейтинг: Рейтинг темы: голосов - 30, средняя оценка - 4.97
sofen
0 / 0 / 0
Регистрация: 31.10.2010
Сообщений: 45
#1

Реализация событий в С++ - C++

02.11.2010, 08:56. Просмотров 4047. Ответов 15
Метки нет (Все метки)

Мне нужно реализовать события, как в Дельфи или С++ Builder, на Visual C++. Но стандартный С++ не поддерживает указатели на функции-члены класса. В своём блоге за 02.11.10, я попытался расписать, как это можно было бы реализовать, но получилось уж слишком громоздко... А как сделать проще?
После регистрации реклама в сообщениях будет скрыта и будут доступны все возможности форума.
volovzi
267 / 169 / 8
Регистрация: 14.03.2010
Сообщений: 501
02.11.2010, 12:26     Реализация событий в С++ #2
Как это не поддерживает? Вот примеры:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#include <iostream>
#include <functional>
 
struct A {
    A (int y) : x(y) {}
 
    void print_x () const { std::cout << x << std::endl; }
    
    int x;
};
 
int main (int argc, char * const argv[]) {
    A a(17);
 
    typedef void (A::*method) () const;
    method fp = &A::print_x;
    
    (a.*fp)();
    //или
//  std::mem_fun(fp)(&a); // Этот вариант можно использовать и в алгоритмах.
 
    return 0;
}
Добавлено через 22 минуты
Полиморфизм:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#include <iostream>
#include <functional>
 
struct A {
    virtual void show () const { std::cout << "A::show()" << std::endl; }
};
 
struct B : A {
    void show () const { std::cout << "B::show()" << std::endl; }
};
 
int main (int argc, char * const argv[]) {
    A * a = new B;
 
    typedef void (A::*method) () const;
    method fp = &A::show;
    
//  (a->*fp)();
    //или
    std::mem_fun(fp)(a); // Этот вариант можно использовать и в алгоритмах.
 
    return 0;
}
Статические функции:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include <iostream>
 
struct A {
    static int get_num () { return 1; }
};
 
int main (int argc, char * const argv[]) {
    typedef int (* static_f_ptr) ();
    static_f_ptr fp = A::get_num;
 
    std::cout << fp() << std::endl;
 
    return 0;
}
CyBOSSeR
Эксперт C++
2299 / 1669 / 86
Регистрация: 06.03.2009
Сообщений: 3,675
02.11.2010, 13:48     Реализация событий в С++ #3
sofen.ru, используй boost::function. Она может привязываться к свободным функциям, функторам, методам. И посмотри в сторону Boost.Signals.
sofen
0 / 0 / 0
Регистрация: 31.10.2010
Сообщений: 45
02.11.2010, 14:51  [ТС]     Реализация событий в С++ #4
void print_x () const { std::cout << x << std::endl; }
если убираю const, то не работает )

а мне надо вызывать ещё и виртуальную функцию)

полиморфизм и статические функции не катят)
буст тоже не подходит... Так как я пишу свою библиотеку, то завязывание на чужие либы (будь то буст или другая) никак не приемлемо... Я всем представляю либу, которая будет весить едва ли метр, но для её работы необходимо скачать несколько различных других библиотек на десятки или сотни килобайтов)))

К сожалению, админ удалил ссылку на мой блог ))) скидываю с него текст...


Реализация событий в С++

Опять столкнулся с проблемой, что в стандартном С++ нет указателя на функции, являющиеся членами класса (хотя есть указатель на обычную функцию). Для чего они могут понадобиться? На них можно было бы реализовать события, например, событие нажатия кнопки.

Пришлось пойти громоздким, но более-менее понятным путём. Для начала описываем класс события.

C++
1
2
3
4
5
6
7
8
9
10
11
template  class Event
{
public:
    Object *owner;
    T event;
    void set(Object *owner, T event)
    {
        this->owner = owner;
        this->event = event;
    }
};
Теперь опишем, тип “указатель на функцию”.

C++
1
typedef void (*ClickFunc)(Object *owner, Object *sender);
Затем, опишем тип «событие нажатия».

C++
1
typedef Event ClickEvent;
Ну пусть будет так… Как же теперь этим пользоваться?

Описываем классе кнопке Button событие onClick.

C++
1
2
3
4
class Button : Control {
public:
    ClickEvent onClick;
};
Во классе форме Form, где будет располагаться кнопка, описываем статическую функцию и обычную нормальную функцию, которую необходимо вызвать по событию.

C++
1
2
3
4
5
6
7
8
9
10
11
12
class Form {
public:
    static void stMyClick(Object *owner, Object *sender);
    virtual void myClick(Object *sender);
};
void Form::stMyClick(Object *owner, Object *sender) {
    ((CMy2*)owner)->myClick(Sender);
    
}
void Form::myClick(Object *sender) {
    //Код, выполняющийся по событию
}
Далее, в реализации какой-либо функции (или, например, в конструкторе) класса Form пишем следующее:

C++
1
2
Button *btn = new Button();
btn->onClick.set(this, stMyClick);
А уже в менеджере, который будет обрабатывать события, пишем следующее:

C++
1
if  (control->OnClick.event != NULL) control->OnClick.event(owner, sender);
Мдааа... Жесть...
volovzi
267 / 169 / 8
Регистрация: 14.03.2010
Сообщений: 501
02.11.2010, 15:26     Реализация событий в С++ #5
Цитата Сообщение от sofen Посмотреть сообщение
если убираю const, то не работает )
Епстессно, сигнатура же изменилась.

а мне надо вызывать ещё и виртуальную функцию)
Про виртуальные я уже писал.

полиморфизм и статические функции не катят)
Ты о чём?

буст тоже не подходит... Так как я пишу свою библиотеку, то завязывание на чужие либы (будь то буст или другая) никак не приемлемо... Я всем представляю либу, которая будет весить едва ли метр, но для её работы необходимо скачать несколько различных других библиотек на десятки или сотни килобайтов)))
Перед тем, как писать свою библиотеку, не мешало бы изучить имеющийся у человечества опыт.
sofen
0 / 0 / 0
Регистрация: 31.10.2010
Сообщений: 45
02.11.2010, 15:35  [ТС]     Реализация событий в С++ #6
volovzi, спасибо... не уверен, но вроде работает... сейчас разбираюсь...
tartikov
Заблокирован
02.11.2010, 15:54     Реализация событий в С++ #7
Цитата Сообщение от sofen Посмотреть сообщение
Мдааа... Жесть...
точно

информациии на эту тему - куча, прежде чем городить свой велосипед, надо что-нибудь почитать, посмотреть как сделано у других.

- boost::function, signals - уже советовали, наверно самое лучшее, и универсальное решение.
- Functor из книги Андрея Александреску.
- Гамма, "паттерны проектирования" - паттерн Command
- http://dobrokot.nm.ru/cpp/closure.zip - реализация от товарища Winnie, советую обратить особое внимание, если не хочешь тащить в проект тяжелые библиотеки вроде буста
sofen
0 / 0 / 0
Регистрация: 31.10.2010
Сообщений: 45
02.11.2010, 16:23  [ТС]     Реализация событий в С++ #8
volovzi, а как заставить работать следующий код?
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
#include <iostream>
 
class Object {
public:
    Object() {}
};
class Button : public Object {
public:
    Button() {}
    EventClick onClick; // Нужно перед этим как-то описать EventClick 
};
class Form : public Object {
public:
    Form() {}
    virtual void out(int value) { 
        std::cout << value << std::endl;
    }
};
int main(int argc, char* argv[])
{
    Form *form = new Form();
    Button *button = new Button();
    button->onClick = form->out; // Эта функция должна вызываться по событию onClick кнопки button
    button->onClick(10); // вызываем событие нажатия кнопки с каким-то параметром
    return 0;
}
tartikov, спасибо... кажись, то что и нужно... бум смотреть...
oxotnik
1586 / 1063 / 33
Регистрация: 21.08.2008
Сообщений: 4,545
Записей в блоге: 1
02.11.2010, 16:29     Реализация событий в С++ #9
Наблюдатель - паттерн
tartikov
Заблокирован
02.11.2010, 17:45     Реализация событий в С++ #10
Цитата Сообщение от sofen Посмотреть сообщение
а как заставить работать следующий код?
если использовать Winnie.Closure, то этот код будет выглядеть так
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
#include <iostream>
#include "closure.h"
 
class Object {
public:
    Object() {}
};
 
typedef Closure<void(int)> EventClick;
 
class Button : public Object {
public:
    Button() {}
    EventClick onClick; // Нужно перед этим как-то описать EventClick 
};
 
class Form : public Object {
public:
    Form() {}
    virtual void out(int value) { 
        std::cout << value << std::endl;
    }
};
 
int main(int argc, char* argv[])
{
    Form *form = new Form();
    Button *button = new Button();
    button->onClick = CLOSURE(form, &Form::out);
    button->onClick(10);
    return 0;
}
sofen
0 / 0 / 0
Регистрация: 31.10.2010
Сообщений: 45
02.11.2010, 22:55  [ТС]     Реализация событий в С++ #11
tartikov, ну что могу сказать... оно работает!

Посмотрел исходник closure.h и closure_impl.h - я в шоке!

Надо будет книжку полистать по С++ - загладить пробелы


Да, кстати, я слово CLOSURE заменил на getEvent, а Closure на Event ... теперь получилось симпотишно, как мне и надо было:

C++
1
2
3
4
5
typedef Event<void(int)> EventClick;
...
EventClick onClick;
...
button->onClick = getEvent(form, &Form::out);
tartikov
Заблокирован
03.11.2010, 00:15     Реализация событий в С++ #12
sofen, можно вопрос, а что у вас за класс Object, какие методы в него можно запихнуть, которые будут нужны всем объектам? Мне в голову ничего не приходит кроме как подсчет ссылок.
sofen
0 / 0 / 0
Регистрация: 31.10.2010
Сообщений: 45
03.11.2010, 10:19  [ТС]     Реализация событий в С++ #13
tartikov, методы runtime и сериализации...

Добавлено через 10 минут
Но это даже не главное. Главное, чтобы все мои классы были порождены от одного класса.

Спросите зачем? Уже и не помню. Вошло в привычку...

Добавлено через 4 часа 29 минут
tartikov, тут такой, на самом деле, очень важный вопрос... а как присвоить событию опять NULL ???
tartikov
Заблокирован
03.11.2010, 17:29     Реализация событий в С++ #14
Цитата Сообщение от sofen Посмотреть сообщение
tartikov, тут такой, на самом деле, очень важный вопрос... а как присвоить событию опять NULL ???
можно так
button->onClick = EventClick();
но тогда, при вызове приходится проверять
if(button->onClick) button->onClick(10);

Добавлено через 4 часа 35 минут
почему то в этой библиотеке у Closure нету оператора==.
если самому дописать его, то можно замутить такую штуку.
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
#include "closure.h"
#include <iostream>
#include <algorithm>
#include <vector>
 
template <class F>
class Signal
{
    typedef Closure<F> E; 
    typedef std::vector<E> EventsVector;
public:
 
    void operator+= (const E& event)
    {
        events.push_back(event);
    }
    void operator-= (const E& event)
    {
        events.erase(std::remove(events.begin(), events.end(), event), events.end());
    }
    void clear()
    {
        events.clear();
    }
 
    template<class A0>
    void operator()(const A0& a0)
    {
        for(EventsVector::iterator i = events.begin(); i != events.end(); ++i)
        {
            (*i)(a0);
        }
    }
    template<class A0, class A1>
    void operator()(const A0& a0, const A1& a1)
    {
        for(EventsVector::iterator i = events.begin(); i != events.end(); ++i)
        {
            (*i)(a0, a1);
        }
    }
    /* и так далее для стольки аргументов, сколько нужно*/
private:    
    EventsVector events;
};
 
 
class Form
{
public:
    void out1(int value) 
    { 
        std::cout << "out1 "<< value << std::endl;
    }
    void out2(int value) 
    { 
        std::cout << "out2 "<< value << std::endl;
    }
};
 
int main(int argc, char* argv[])
{
 
    Form form;
    Signal<void(int)> s;
    s += CLOSURE(&form, &Form::out1);
    s += CLOSURE(&form, &Form::out2);
    s(10);
    
    s -= CLOSURE(&form, &Form::out1);
    s(20);
    
    s.clear();
    s(30);
}
oxotnik
1586 / 1063 / 33
Регистрация: 21.08.2008
Сообщений: 4,545
Записей в блоге: 1
04.11.2010, 10:53     Реализация событий в С++ #15
Люди, выложите исходники Closure, а то чет по ссылке ничего не вижу. Страсть как охота посмотреть.
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
04.11.2010, 15:04     Реализация событий в С++
Еще ссылки по теме:

C++ Builder Добавление событий
Обработка событий кнопки C++ Builder
Boost C++ Реализация ожжидания сразу двух событий
Реализация журнала ошибок и протоколирования событий C++

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

Или воспользуйтесь поиском по форуму:
tartikov
Заблокирован
04.11.2010, 15:04     Реализация событий в С++ #16
oxotnik, странно, сейчас проверил - ссылка рабочая
вот выложил в другом месте

 Комментарий модератора 
Во избежании потери информации на сторонних ресурсах загружайте файлы на форум через Вложения в Расширенном режиме редактирования сообщений.
Вложения
Тип файла: zip closure.zip (2.5 Кб, 38 просмотров)
Yandex
Объявления
04.11.2010, 15:04     Реализация событий в С++
Ответ Создать тему
Опции темы

Текущее время: 05:00. Часовой пояс GMT +3.
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2017, vBulletin Solutions, Inc.
Рейтинг@Mail.ru