0 / 0 / 1
Регистрация: 31.10.2010
Сообщений: 45
1

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

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

Мне нужно реализовать события, как в Дельфи или С++ Builder, на Visual C++. Но стандартный С++ не поддерживает указатели на функции-члены класса. В своём блоге за 02.11.10, я попытался расписать, как это можно было бы реализовать, но получилось уж слишком громоздко... А как сделать проще?
__________________
Помощь в написании контрольных, курсовых и дипломных работ, диссертаций здесь
0
Programming
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
02.11.2010, 08:56
Ответы с готовыми решениями:

Реализация журнала ошибок и протоколирования событий
Добрый день, уважаемое сообщество. При написании выпускной работы появилась необходимость вести...

Тетрис - Реализация таймера и обработка событий с клавиатуры
Пишу консольный тетрис. Столкнулся с проблемой таймера и перехвата событий с клавиатуры. Раньше с...

Реализация программы на С++ (Найти вероятности следующих событий:)
Помогите пожалуйста реализовать на С++ или на С# программу по этой задаче N стрелков...

Реализация ожжидания сразу двух событий
Допустим есть три потока, один из которыйх должен ждать наступления одного из двух событий и...

15
274 / 175 / 12
Регистрация: 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;
}
0
Эксперт С++
2343 / 1716 / 148
Регистрация: 06.03.2009
Сообщений: 3,675
02.11.2010, 13:48 3
sofen.ru, используй boost::function. Она может привязываться к свободным функциям, функторам, методам. И посмотри в сторону Boost.Signals.
0
0 / 0 / 1
Регистрация: 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);
Мдааа... Жесть...
0
274 / 175 / 12
Регистрация: 14.03.2010
Сообщений: 501
02.11.2010, 15:26 5
Цитата Сообщение от sofen Посмотреть сообщение
если убираю const, то не работает )
Епстессно, сигнатура же изменилась.

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

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

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

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

- boost::function, signals - уже советовали, наверно самое лучшее, и универсальное решение.
- Functor из книги Андрея Александреску.
- Гамма, "паттерны проектирования" - паттерн Command
- http://dobrokot.nm.ru/cpp/closure.zip - реализация от товарища Winnie, советую обратить особое внимание, если не хочешь тащить в проект тяжелые библиотеки вроде буста
0
0 / 0 / 1
Регистрация: 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, спасибо... кажись, то что и нужно... бум смотреть...
0
1664 / 1133 / 80
Регистрация: 21.08.2008
Сообщений: 4,725
Записей в блоге: 1
02.11.2010, 16:29 9
Наблюдатель - паттерн
0
Заблокирован
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;
}
1
0 / 0 / 1
Регистрация: 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);
0
Заблокирован
03.11.2010, 00:15 12
sofen, можно вопрос, а что у вас за класс Object, какие методы в него можно запихнуть, которые будут нужны всем объектам? Мне в голову ничего не приходит кроме как подсчет ссылок.
0
0 / 0 / 1
Регистрация: 31.10.2010
Сообщений: 45
03.11.2010, 10:19  [ТС] 13
tartikov, методы runtime и сериализации...

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

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

Добавлено через 4 часа 29 минут
tartikov, тут такой, на самом деле, очень важный вопрос... а как присвоить событию опять NULL ???
0
Заблокирован
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);
}
0
1664 / 1133 / 80
Регистрация: 21.08.2008
Сообщений: 4,725
Записей в блоге: 1
04.11.2010, 10:53 15
Люди, выложите исходники Closure, а то чет по ссылке ничего не вижу. Страсть как охота посмотреть.
0
Заблокирован
04.11.2010, 15:04 16
oxotnik, странно, сейчас проверил - ссылка рабочая
вот выложил в другом месте

 Комментарий модератора 
Во избежании потери информации на сторонних ресурсах загружайте файлы на форум через Вложения в Расширенном режиме редактирования сообщений.
Вложения
Тип файла: zip closure.zip (2.5 Кб, 68 просмотров)
1
IT_Exp
Эксперт
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
04.11.2010, 15:04
Помогаю со студенческими работами здесь

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

Клиент OLE Automation, реализация класса стока событий
Всем привет. Задача такая, есть сервер и клиент OLE Automation. У сервера есть несколько событий,...

Сгенерировать 30 случайных событий с интенсивностью 10 событий в час с помощью мастера функций
Добрый день! Помогите решить.:( Задача: Сгенерировать 30 случайных событий с интенсивностью 10...

Суммой двух событий А и В называется событие С, состоящее…1) в наступлении хотя бы одного из событий А и В2
Суммой двух событий А и В называется событие С, состоящее… 1) в наступлении хотя бы одного из...


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

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

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2022, CyberForum.ru