Модераторы: Daevaorn

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Есть ли события в С++?.. или их аналог?.. 
:(
    Опции темы
S.A.P.
Дата 13.11.2005, 15:17 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Участник Клуба
Сообщений: 2664
Регистрация: 11.6.2004

Репутация: 9
Всего: 71



Цитата(powerfox @ 13.11.2005, 14:16)
To Perchilla:
Не могли бы Вы дать пояснения к коду?

тут я просто создал объект функцию (сигнал) с перегруженным оператором (), к которому можно подключать другие функции (слоты). Для подключения слотов я перегрузил оператор <= (для наглядности). Указатели на слоты храняться в контейнере std::vector. При имитировании сигнала ( signal() ) соответственно вызываются все слоты, которые былы подключены. То есть как в QT, например при нажатии на QPushButton имитируется сигнал clicked().

Но мой пример не очень хорош, чаще требуется передавать какие - то параметры из сигнала в слоты ( например координаты, как у Kurt ). Для частного случая можно и напильником подогнать, но если в одном классе надо держать несколько сигналов с разныи количеством параметров, то лучше написать шаблон. Вот только в шаблонах я пока плаваю smile и не могу понять как правильно это сделать: перегрузить шаблоны для разного количества параметров или можно как то хитро обойти одним шаблоном.

Еще бы не мешало предотвращать попытки повторного подключения слота, дать возможность отключение определенного слота, сделать, чтобы сигнал мог возвращать значения... Но все это больше похоже на переписывание boost::signals.

А вот интересно, как в boost сделали передачу параметров в слоты. Знаю, что в QT это реализовано на уровне препроцессора, что немного огорчает smile .
PM MAIL   Вверх
Дмитрий Т
Дата 13.11.2005, 20:44 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 93
Регистрация: 16.3.2005
Где: Самара

Репутация: 4
Всего: 4



Цитата(Kurt @ 13.11.2005, 00:59)
Не спорю, в QT все классно сделали, но, увы, я работаю с GTK.

Кстати, как помню, на qt-шном сайте видел обсуждение по поводу событий, что ради совместимости со старыми наработками разработчики отказываются заменить систему на более эффективную... А на www.fox-toolkit.org утверждается, что в FOX самая лучшая система событий, но я лично не анализировал (по другим причинам выбрал WxWidgets).
PM MAIL WWW ICQ Skype   Вверх
Дмитрий Т
Дата 13.11.2005, 21:00 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 93
Регистрация: 16.3.2005
Где: Самара

Репутация: 4
Всего: 4



Цитата(Perchilla @ 13.11.2005, 16:17)
... но если в одном классе надо держать несколько сигналов с разныи количеством параметров, то лучше написать шаблон. Вот только в шаблонах я пока плаваю  smile и не могу понять как правильно это сделать: перегрузить шаблоны для разного количества параметров или можно как то хитро обойти одним шаблоном.


Может не шаблон, а несколько классов?
Посмотри раздел Events на
http://wxwidgets.org/manuals/2.6.2/wx_clas...ml#classesbycat
у этой достаточно старой и распространённой библиотеки есть иерархия типов событий...
PM MAIL WWW ICQ Skype   Вверх
S.A.P.
Дата 14.11.2005, 08:20 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Участник Клуба
Сообщений: 2664
Регистрация: 11.6.2004

Репутация: 9
Всего: 71



Цитата
Может не шаблон, а несколько классов?

просто все мои представления об этом отталкиваются от boost::signals, а там можно так записать:
Код

void print_sum(float x, float y)
{
  std::cout << "The sum is " << x+y << std::endl;
}

void print_product(float x, float y)
{
  std::cout << "The product is " << x*y << std::endl;
}

void print_difference(float x, float y)
{
  std::cout << "The difference is " << x-y << std::endl;
}

void print_quotient(float x, float y)
{
  std::cout << "The quotient is " << x/y << std::endl;
}

// . . . 

boost::signal<void (float, float)> sig;

sig.connect(&print_sum);
sig.connect(&print_product);
sig.connect(&print_difference);
sig.connect(&print_quotient);

sig(5, 3);

PM MAIL   Вверх
srd
Дата 14.11.2005, 13:05 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Нереварин
**


Профиль
Группа: Участник Клуба
Сообщений: 951
Регистрация: 30.8.2003
Где: Владивосток

Репутация: 27
Всего: 49



Цитата
А на www.fox-toolkit.org утверждается, что в FOX самая лучшая система событий, но я лично не анализировал (по другим причинам выбрал WxWidgets).

В FOX Toolkit такое же мракобесие на макросах, как в wxWidgets или MFC.


--------------------
Не смей читать мою подпись!!!
PM MAIL Jabber   Вверх
Guest
Дата 15.11.2005, 14:51 (ссылка)    |    (голосов: 0) Загрузка ... Загрузка ... Быстрая цитата Цитата


Unregistered











Цитата(Perchilla @ 14.11.2005, 08:20)
Цитата
Может не шаблон, а несколько классов?

просто все мои представления об этом отталкиваются от boost::signals, а там можно так записать:
Код

void print_sum(float x, float y)
{
  std::cout << "The sum is " << x+y << std::endl;
}

void print_product(float x, float y)
{
  std::cout << "The product is " << x*y << std::endl;
}

void print_difference(float x, float y)
{
  std::cout << "The difference is " << x-y << std::endl;
}

void print_quotient(float x, float y)
{
  std::cout << "The quotient is " << x/y << std::endl;
}

// . . . 

boost::signal<void (float, float)> sig;

sig.connect(&print_sum);
sig.connect(&print_product);
sig.connect(&print_difference);
sig.connect(&print_quotient);

sig(5, 3);

А где здесь события с разным количеством аргументов? Вроде тоже самое только тип задаётся с помошью шаблона.
  Вверх
S.A.P.
Дата 15.11.2005, 17:05 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Участник Клуба
Сообщений: 2664
Регистрация: 11.6.2004

Репутация: 9
Всего: 71



Цитата(Guest @ 15.11.2005, 14:51)
А где здесь события с разным количеством аргументов? Вроде тоже самое только тип задаётся с помошью шаблона.
разница в том, что я юзая один класс могу создать сигналы с разлиным количеством параметров. Количество параметров у слотов разумеется должно быть одинаково. Правда в QT это не обязательно, но это другая тема.

PM MAIL   Вверх
nikf
Дата 15.11.2005, 20:57 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 127
Регистрация: 6.6.2005
Где: город-герой Жирно вск

Репутация: нет
Всего: 1



делегаты в .net не более чем функции обратного вызова в си. а нагородили-то на три страницы...QT приплели...

Это сообщение отредактировал(а) nikf - 15.11.2005, 20:58
PM MAIL   Вверх
Void
Дата 15.11.2005, 21:04 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


λcat.lolcat
****


Профиль
Группа: Участник Клуба
Сообщений: 2206
Регистрация: 16.11.2004
Где: Zürich

Репутация: 40
Всего: 173



Цитата(nikf @ 15.11.2005, 22:57)
делегаты в .net не более чем функции обратного вызова в си.

Для Си все просто. А вот для C++ аналогом делегатов дотнета является boost::function + bind'еры. Потому что метод объекта сам по себе не является вызываемой сущностью.


--------------------
“Coming back to where you started is not the same as never leaving.” — Terry Pratchett
PM MAIL WWW GTalk   Вверх
nikf
Дата 15.11.2005, 21:37 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 127
Регистрация: 6.6.2005
Где: город-герой Жирно вск

Репутация: нет
Всего: 1



Цитата(Void @ 15.11.2005, 21:04)
А вот для C++ аналогом делегатов дотнета является boost
boost это библиотека, а не язык, вопрос про язык был, а библиотек всяких разных в том числе и boost достаточно много. от этого они не становятся стандартом языка

PM MAIL   Вверх
Void
Дата 15.11.2005, 21:45 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


λcat.lolcat
****


Профиль
Группа: Участник Клуба
Сообщений: 2206
Регистрация: 16.11.2004
Где: Zürich

Репутация: 40
Всего: 173



nikf
Хорошо. Аналогом делегатов дотнета является boost::function или близкая по функциональности библиотека. Так устраивает? В C++ нет примитивов, позволяющих решить поставленную задачу.
Цитата(nikf @ 15.11.2005, 23:37)
от этого они не становятся стандартом языка

Почти стали. Посмотри TR1 по стандартной библиотеке.


--------------------
“Coming back to where you started is not the same as never leaving.” — Terry Pratchett
PM MAIL WWW GTalk   Вверх
mes
Дата 18.3.2008, 17:41 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


любитель
****


Профиль
Группа: Участник Клуба
Сообщений: 7954
Регистрация: 14.1.2006

Репутация: 144
Всего: 250



Иногда удобно применять подход описанный ниже. Как называется не знаю. Но цель вынести обшую функционалость в обший класс обработчик.
Состоит из трех частей : 
1 определение типов сообшений,так чтоб их объект содержал нужную информацию о событии - например в описанной ниже хранится координаты покинутой клетки и той на которую перепрыгнул объект
2. Интерфейс обработчика сообшений - состоид из двух частей
а. перегруженный метод (в примере OnEvt) для диспатчеризации нужного типа нужному обработчику
б. виртуальный метод  - обработчик события 
3. сам объект

Преимушества :
1. Типизация которая не даст допустить ошибку.
2..  двойная диспетчиризация, что позволяет раздельно развивать, но совместно использовать  сами обьекты и лабиринты.
3.  логика обработки событий сгруппированна в одном месте. 
4.  информация собирается в момент происхождения события а не в момент обработки
6.  *..
Недостатки:
1. нужна проектировка классов (что в принципе желательно при любом подходе)
2. естественно не потокобезопасная
3 *..
 *..  = может есть что то еше - сейчас не пришло в голову 


Код

namespace Evt {
struct SObjectMoved 
{
  SObjectMoved (SCoord oldcell, newcell) :oldCell (oldcell), newCell (oldCell)
  SCoord  oldCell;
  SCoord newCell;
}
};

class GameObject {...}; // то что движется по лабиринту

class LabirintEvt
{
   public :  
     void OnEvt (const Evt::SObjectMoved& evt,   GameObject* pobj) { doOnObjectMovedEvt(evt,pobj); };  // перегрузка функций для разных событий
     void OnEvt (...)
  protected: 
     void doOnObjectMovedEvt (const Evt::SObjectMoved& evt,   GameObject* pobj) =0;
}

class Pacman : public GameObject {..}  *pPacman;
//где внутри цикла
if (pEvt) pEvt->OnEvt (Evt::SObjectMoved(SCooord(2,1),SCooord(2,2)), pPacman )





--------------------
PM MAIL WWW   Вверх
Дмитрий Т
Дата 19.3.2008, 09:55 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 93
Регистрация: 16.3.2005
Где: Самара

Репутация: 4
Всего: 4



Цитата(mes @ 18.3.2008,  18:41)
Иногда удобно применять подход описанный ниже. Как называется не знаю. Но цель вынести обшую функционалость в обший класс обработчик.
[/code]

Насколько понял, вы просто вынесли код события в отдельное дерево классов начинающееся с LabirintEvt. Не совсем понятно когда такой подход удобен... Если есть объект Лабиринт и объект Человечек, то для рекции Лабиринта на движения Человечка достаточно в одном классе создать указатель на функцию...
PM MAIL WWW ICQ Skype   Вверх
mes
Дата 19.3.2008, 15:09 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


любитель
****


Профиль
Группа: Участник Клуба
Сообщений: 7954
Регистрация: 14.1.2006

Репутация: 144
Всего: 250



Цитата(Дмитрий Т @  19.3.2008,  09:55 Найти цитируемый пост)
Не совсем понятно когда такой подход удобен

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

Цитата(Дмитрий Т @  19.3.2008,  09:55 Найти цитируемый пост)
для рекции Лабиринта на движения Человечка

вобше сообшения предназначены не столько для реакции Лабиринта на движения Человечка   
сколько для реакции "внешних" компонентов на взаимоотношение между Человечком и Лабиринтом.


Пример: Главное окно разбито на несколько компонентов . В одном отображен сам процесс игры, в других информация о игре: координаты объекта , список ходов и т.д.

Код


template <class T>
class TCluster 
{
typedef std::set<T> TEvtSet;
public:
template <class P> void OnEvt (P p1) { for (TEvtSet::iterator it = m_set.begin(); it!=m_set.end(); ++it) { if (*it)  (*it)->OnEvt(p1); }  
.. //здесь для двух и более параметров
void insert (T pevt) {m_set.insert(pevt); }
void erase (T pevt) {m_set.erase(pevt); }
private:
TEvtSet m_set;

};

class CGame
{
public:
 void MoveGameObject (int id, SCoord coord) { if (doMove(...)==success) m_LabirintEvtCluster.OnEvt (SObjectMoved (... ); } // множественная рассылка
void insert (ILabirintEvt * pEvt) {m_LabirintEvtCluster.insert (pEvt); }
void erase (ILabirintEvt * pEvt) {m_LabirintEvtCluster.erase (pEvt); }
private:
     TCluster<ILabirintEvt> m_LabirintEvtCluster;
...
};

class WGamePanel // образец визуального компонента
                                     : public WPanel , protected ILabirintEvt // двойное наследие для упрошения при использовании одного контролера на виджет
{
public:
           WActionScene (WWindow *parent, ..., CGame *pgame) { pgame ->insert((ILabirintEvt*)this); } 
            virtual ~WActionScene (WWindow *parent, ..., CGame *pgame) { pgame ->erase((ILabirintEvt*)this); }
 protected: 
        doOn...Evt ... { }
      ..
}; 
class WActionScene : ... // окно процесса игры 
class WHistory:              // панель с показом ходов
class WCoord :           // текушее положение
..                                  // что нибудь еше

class CStatusBarCtrl: protected ILabirintEvt  // классическое применение контролера событий
{
public:
    CStatusBarCtrl(WStatusBar* pbar, CGame *pgame) : p_bar(pbar) { pgame->insert (this); }
...
private:
WSatatusBar *p_bar;
};

class WMainFame : WFrame  // главное окно
{
public:
...

protected:
  void CreateContols () {  new WActionScene (this,..., &m_Game); // создание компонента на главном окне с получением событием от лабиринта
                                             WPanel *  pwPanel = new WPanel (this) ;// к примеру боковая панель 
                                             new WHistory (pwPanel,..., &m_Game); //создание компонента на боковой панели, но он все так же будет получать сообшения                                 
                                             pStBarCtrl = newCStatusBarCtrl(this->GetStatusBar(), &m_Game);
                                        };
private:
     CGame m_Game;
      CStatusBarCtrl * pStBarCtrl;
};

};


* Пример привел в обшей схеме с упрошениями для легкого представления.. 
названия выбраны условн, приставка W - означает виджет.
Преимушество приведенного примера : реализация визуализации отделена от реализации логики игры.
 



Это сообщение отредактировал(а) mes - 19.3.2008, 15:17


--------------------
PM MAIL WWW   Вверх
Дмитрий Т
Дата 21.3.2008, 10:40 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 93
Регистрация: 16.3.2005
Где: Самара

Репутация: 4
Всего: 4



А здесь не тоже самое http://docs.wxwidgets.org/stable/wx_classe...ml#classesbycat дерево начинающееся с Events?
PM MAIL WWW ICQ Skype   Вверх
Страницы: (4) Все 1 2 [3] 4 
Ответ в темуСоздание новой темы Создание опроса
Правила форума "С++:Общие вопросы"
Earnest Daevaorn

Добро пожаловать!

  • Черновик стандарта C++ (за октябрь 2005) можно скачать с этого сайта. Прямая ссылка на файл черновика(4.4мб).
  • Черновик стандарта C (за сентябрь 2005) можно скачать с этого сайта. Прямая ссылка на файл черновика (3.4мб).
  • Прежде чем задать вопрос, прочтите это и/или это!
  • Здесь хранится весь мировой запас ссылок на документы, связанные с C++ :)
  • Не брезгуйте пользоваться тегами [code=cpp][/code].
  • Пожалуйста, не просите написать за вас программы в этом разделе - для этого существует "Центр Помощи".
  • C++ FAQ

Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, Earnest Daevaorn

 
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | C/C++: Общие вопросы | Следующая тема »


 




[ Время генерации скрипта: 0.1467 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.