![]() |
Внимание, важное сообщение: Дорогие Друзья!
В ноябре далекого 2001 года мы решили создать сайт и форум, которые смогут помочь как начинающим, так и продвинутым пользователям разобраться в операционных системах. В 2004-2006г наш проект был одним из самых крупных ИТ ресурсов в рунете, на пике нас посещало более 300 000 человек в день! Наша документация по службам Windows и автоматической установке помогла огромному количеству пользователей и сисадминов. Мы с уверенностью можем сказать, что внесли большой вклад в развитие ИТ сообщества рунета. Но... время меняются, приоритеты тоже. И, к сожалению, пришло время сказать До встречи! После долгих дискуссий было принято решение закрыть наш проект. 1 августа форум переводится в режим Только чтение, а в начале сентября мы переведем рубильник в положение Выключен Огромное спасибо за эти 24 года, это было незабываемое приключение. Сказать спасибо и поделиться своей историей можно в данной теме. С уважением, ваш призрачный админ, BigMac... |
|
Компьютерный форум OSzone.net » Программирование, базы данных и автоматизация действий » Программирование и базы данных » Callback - Опять в раздумьях |
|
Callback - Опять в раздумьях
|
![]() Ветеран Сообщения: 1180 |
Тема уже была, но хочется свежего вгляда. Если можно, технические аргументы (в смысле не так, что в такой-то библиотеке так-то, а почему так лучше).
Как лучше сделать callback? 1. через виртуальные классы. Экономит память, работает быстро, но много писанины. class callback_t {public virtual void fire(...) = 0;} class A { struct callback1 : callback { A* a; callback1(A* a1) : a(a1) {} void fire(...) {a->doSomething(...);} }; // и так на каждый callback ... }; typedef void (Object::*callback)(...); class Object1 : public Object {...} // трудно привести void (Object1::*callback)(...) к void (Object::*callback)(...), нужен хак. Промойте мне мозги, please |
|
Отправлено: 21:28, 25-05-2006 |
редкий гость Сообщения: 1696
|
Профиль | Сайт | Отправить PM | Цитировать Ничего не могу сказать, кроме того, что я однозначно против таблиц диспечерезации. Сам использовал только первый вариант, потому что понятие callback в первый раз встретил именно с подбной реализацией. Если раздражает много писать (и параметры всё равно у всех одинаковые), то можно написать например такой шаблон:
template <typename T> struct member_callback : callback { typedef void (T::*ptr) (/*whatever*/); T *obj; ptr method; member_callback(T *o, ptr m) : obj(o), method(m) {} void fire(/*whatever*/) { (obj->*method)(/*whatever*/); } }; Да и макросы не зря были придуманы... |
------- Отправлено: 22:13, 25-05-2006 | #2 |
Для отключения данного рекламного блока вам необходимо зарегистрироваться или войти с учетной записью социальной сети. Если же вы забыли свой пароль на форуме, то воспользуйтесь данной ссылкой для восстановления пароля. |
Старый параноик Сообщения: 2423
|
Профиль | Отправить PM | Цитировать \me - Через виртуальные классы.
но вообще-то я в основном QT юзаю, а там проблема решена уже |
Отправлено: 11:09, 26-05-2006 | #3 |
![]() Ветеран Сообщения: 1180
|
Профиль | Отправить PM | Цитировать Ivank, это получается вариант №2, потому что использует указатель на метод. Я так пробовал. Оптимизация не помогает. А вот с макросами что-то не подумал. Это мысль!
Hasherfrog, я бы не заморачивался, имея бесплатный QT под виндами (хотя там сделано вариантом №3). Как всегда, ответили самые уважаемые мной люди. Спасибо. Попробую с define-ом. |
Отправлено: 22:53, 26-05-2006 | #4 |
Старый параноик Сообщения: 2423
|
Профиль | Отправить PM | Цитировать Вот жеж :] Столкнулся с очень похожей задачей (уже решил, но второпях, абы работало, "горю"; вот хочу поговорить "за красоту решения")
1) Есть класс А, сложно-навороченный. Можифицировать его невозможно. Он периодически генерирует некое событие, назовём event. 2) Есть класс В (который можно модифицировать, это "наш" класс), который должен отслеживать event и корректировать собственные переменные в соответствии с новыми данными от event. 3) Класс А не имеет внешних сношений с миром кроме как через класс С, который имеет конструктор С::С(А) и виртуальный метод onEvent(). Собственно, С::onEvent() вызывается классом А, сразу после event'а. Модифицировать С нельзя, но можно унаследовать. В общем, не сложно (очень надеюсь, что смог объяснить). Задача: Сделать так, чтобы В тоже получал управление сразу после event'а. Решение сейчас такое: 1) Делаем класс D : public C, в котором переписываем конструктор D::D(A, B*p) : C(A), m_p(p){}; и callback, т.е. D::onEvent() { if(m_p) m_p->onEvent() }; 2) Добавляем callback в класс В (т.е. дописываем B::onEvent(){...}) и заводим в нём переменную D* m_pD = new D(C *pC, this). Теперь скользкий момент. Возникает потребность дописать ещё несколько классов E,F,G... (неизвестно, сколько их будет, в принципе два, но предположим, что их число неограниченно). Они, эти классы, тоже хотят получать event(). Значит, им тоже будет нужен "переписанный" D. Как же оформить D? Сейчас у меня сделано "тупо". Класс D имеет два конструктора D::D(A, B*p) и D::D(A, E*p) и соответственно два члена B*m_pB и E*m_pE. Callback вызывается для того того, который был проинициализирован в конструкторе. Но вот если количество классов будет расти, Вариант 1) написать шаблон tD и использовать {class E; tD<E>cbE; } перед объявлением E,F..., а внутри E использовать cbE (в общем, что-то вроде как у ivank'а) Вариант 2) придётся засовывать в класс D всё новые и новые указатели и fjrward-объявления классов E,F..., а внутри E использовать D Вариант 3) не знаю, ещё чего-нибудь... Как думаете? P.S. QT есть, но классы А и В не имеют слотов/сигналов, они не QObject'ы. Вообще хотелось бы без QT :]]]]]]]]]] P.P.S. pva QT сейчас 4-й грядёт, правда, мы пока не спешим переходить :] |
|
Отправлено: 13:22, 27-05-2006 | #5 |
редкий гость Сообщения: 1696
|
Профиль | Сайт | Отправить PM | Цитировать hasherfrog
Я чего-то не догоняю. Что мешает пронаследовать всех получателей (C, E, F итд) от общего предка и в конструкторе D принимать указатель на этот интерфейс, не заботясь о том, кто его реализует? |
------- Отправлено: 14:17, 27-05-2006 | #6 |
Старый параноик Сообщения: 2423
|
Профиль | Отправить PM | Цитировать ivank
В том-то всё и дело, что не хочется так делать. Некрасиво как-то. Совершенно разные классы, созданные для совершенно разных целей - и вдруг общий предок только для решения такой маленькой фишечки, как поддержка callback'а на event. Это, в принципе, вопрос "психологии и личных вкусов" :-/ >> всех получателей (C, E, F итд) С - нельзя. "Модифицировать С нельзя, ..." Получается, что мы все наши классы B, D, E... наследуем от С. Сторонний программист (который когда-нибудь возможно будет модифицировать и наш код) увидит конструкцию class B : public C, ещё, и ещё... где B - огромный класс, а С - малюсенький и спросит: а на фига? Но проблема не только в этом, не только в "личных пристрастиях" и "заботе" о других разработчиков. Класс С (который не смодифицируешь) обязательно требует в конструкторе ссылку на А. Но что, если мне нужно привязать класс В (унаследованный теперь уже от С, а значит, требующий А в памяти) "на ходу"? Т.е. иметь возможность то "прицепится" к event, то "отцепится"? Или "на ходу" прицепится к одному экземпляру А в памяти, а то к другому? Понимаете? |
Отправлено: 14:30, 27-05-2006 | #7 |
редкий гость Сообщения: 1696
|
Профиль | Сайт | Отправить PM | Цитировать Я немного выше перепутал B и C. Латинские буквы жутко неудобны.
Раз у нас B, E, F, G итд получают одинаковое сообщение, то логично предположить, что в этом аспекте у них одинаковый интерфейс. Почему бы эту одинаковость не вынести в отдельный абстрактный класс? Т.е. схема такая: У нас есть класс I (от слова интерфейс), с функцией onEvent(A &sender). От него наследуются B и компания. D наследуется от C, в конструкторе получает указатель на A и I. Кто этот I реализует - B, E, F или кто ещё ему всё равно. В своём onEvent он вызывает onEvent из I. Всё вроде просто. Если бы можно было менять A я бы вообще просто убрал класс C (и D, соответственно), т.к. они только плодят сущности с моей точки зрения. Другое дело, если события можно привязывать к разным методам. Тогда я не вижу альтернативы написанию нескольких классов вручную/шаблонно/темплейтно, типа того, который я привёл выше. pva Жаль параметром шаблона нельзя сделать отдельный метод, всё могло бы быть значительно красивше. |
------- Отправлено: 16:35, 27-05-2006 | #8 |
Старый параноик Сообщения: 2423
|
Профиль | Отправить PM | Цитировать >> Всё вроде просто.
Да, надо подумать; может, так и сделаю. Thanks. Выглядеть только будет своеобразно, по jav'овски как-то :] |
Отправлено: 18:14, 27-05-2006 | #9 |
![]() Ветеран Сообщения: 1180
|
Профиль | Отправить PM | Цитировать вот так у меня выглядит редактор табличек:
class ListModel { public: virtual void setFocused(item_id_t /*id*/) {}; virtual void setSelected(item_id_t /*id*/, bool) {}; }; class TableEdit; class TableEditModel { public: virtual void erase(const std::vector<item_id_t>&) = 0; virtual void insert() = 0; virtual void select(item_id_t) = 0; virtual void setFocused(item_id_t) = 0; }; class TableEditView : public ListView, ListModel { TableEdit* fpanel; unsigned fcount; void perform(Message&); void setFocused(item_id_t); void setSelected(item_id_t, bool); public: TableEditView(TableEdit* panel); }; class TableEdit : public Panel, ListModel { TableEditModel* fmodel; friend class TableEditView; void focusItem(item_id_t); void setFocused(item_id_t); void eraseSelected(); public: enum { action_select, action_insert, action_erase }; ImageList images; LineLabel label; TableEditView listview; protected: ToolBar toolbar; GridLayout layout; public: TableEdit(Panel&, TableEditModel* model); bool doubleClick(Window*); }; |
Отправлено: 14:41, 31-05-2006 | #10 |
![]() |
Участник сейчас на форуме |
![]() |
Участник вне форума |
![]() |
Автор темы |
![]() |
Сообщение прикреплено |
| |||||
Название темы | Автор | Информация о форуме | Ответов | Последнее сообщение | |
Callback | New DiploBoy | Хочу все знать | 4 | 05-01-2009 00:07 | |
Перенабор callback | DeepProg | Microsoft Windows 2000/XP | 3 | 10-01-2006 14:53 | |
Настройка callback'a | Dimon | Общий по Linux | 12 | 28-02-2004 19:50 | |
Опять ХР, опять вин98, опять сеть =( | Arioch | Сетевые технологии | 7 | 01-04-2003 11:45 | |
Help with Callback, please | LoveGun | Хочу все знать | 2 | 11-12-2002 19:03 |
|