![]() |
|
Модераторы: Daevaorn |
![]()
|
|
| Jcs |
|
|||
|
Unregistered |
Подскажите, пожалуйста, если кто знает, как связать конкретное сообщение (к примеру WM_CREATE) c нестатической функцией-членом класса. Можно, конечно, использовать и статические, выдирая при этом указатель на конкретный экземпляр класса из описателя окна, и вызывая из него нестатическую функцию, но как-то не охота забивать класс парами функций на каждое сообщение. Заранее спасибо.
|
|||
|
||||
| mr.DUDA |
|
|||
|
3D-маньяк ![]() ![]() ![]() ![]() Профиль Группа: Экс. модератор Сообщений: 8244 Регистрация: 27.7.2003 Где: город-герой Минск Репутация: 25 Всего: 232 |
Если програмить на MFC или ATL/WTL, то всё просто - там юзается простой макрос типа BEGIN_MESSAGE_MAP/END_MESSAGE_MAP (или DECLARE_MESSAGE_MAP), внутри него связывается любое сообщение с конкретной нестатической функцией. Или ты про чистый WinAPI ?
-------------------- ![]() |
|||
|
||||
| Jcs |
|
|||
|
Unregistered |
Спасибо за ответ, я про WIN API в чистом виде, в самих MFC к месссаджам привязаны нестатические функции, а я сколько ни пытался, даже указатель на ф-цию-член класса (нестатическую) выдрать не могу... Как они так сделали..
|
|||
|
||||
| RAN |
|
||||||
|
Опытный ![]() ![]() Профиль Группа: Экс. модератор Сообщений: 709 Регистрация: 14.3.2003 Где: Щёлково Моск.обл. Репутация: 5 Всего: 6 |
Это вопрос ко мне. Я уже где-то отвечал. Я делаю так, как ты написал:
Но только я не понял, почему две функиции. Функция одна, и она не статическая. Вот пример класса:
Этот код получился "вырезанием" из реального проекта и исправлением кое-чего. Поэтому возможно что-то не так, но принцип такой. Особенности использования: приходиться вызывать для каждого класса функции RegisterClass и UnregisterClass. Это возможно обойти. Но мне показалось, что так лучше. А так можно в конструкторе класса проверять зарегистрирован класс и если нет, то вызывать RegisterClass. А unregisterclass вообще не вызывать. P.S. Кстати, это класс child-окна. |
||||||
|
|||||||
| Jcs |
|
|||
|
Unregistered |
Это действительно работает, только я пытался избежать использования switch в функции обработки окна. Для этого использовал свой класс CMsgMap, в котором каждому конкретному сообщению сопоствляется своя функция обработки.. Может это, конечно, требуется не всем, но мне в проекте надо функцию обработки генерить на лету, в зависимости от состояния приложения. Но похоже все-таки придется использовать статические функции, передавая им указатель на экземпляр класса. Как выяснилось, нестатические тоже его получают, только при помощи компилятора, так что разницы особой не будет. Спасибо за отклик.
|
|||
|
||||
| RAN |
|
|||
|
Опытный ![]() ![]() Профиль Группа: Экс. модератор Сообщений: 709 Регистрация: 14.3.2003 Где: Щёлково Моск.обл. Репутация: 5 Всего: 6 |
Ну, так давай подумаем вместе. Может чего родится интересное. Напиши поподробнее задачу. |
|||
|
||||
| Unregistered |
|
|||
|
Unregistered |
Изначально задача была - каждому сообщению сопоставить функцию, адрес которой пишется в таблицу сообщений. Обработчик окна должен был искать сообщение в таблице и вызывать соответствующую функцию, причем хотелось, чтобы все функции принимали именно то, что им надо, т.е. OnCreate должна только принимать указатель на структуру LPCREATESTRUCT и больше ничего.
Но так, как придется использовать указатель на функцию, то для каждого такого типа функций нужно будет определять прототипы. Поэтому пока у меня все функции-обрабочики сообщений имеют один тип (принимают HWND,WPARAM и LPARAM), причем если они члены какого-либо класса, то все они статические, так как указатель для нестатических функций-членов получить нельзя. В этой реализации не все удобно, но вроде работает. |
|||
|
||||
| Fantasist |
|
||||
|
Лентяй ![]() ![]() ![]() Профиль Группа: Участник Клуба Сообщений: 1517 Регистрация: 24.3.2002 Репутация: 4 Всего: 41 |
Почему нельзя, все можно. Естесственно, этот указатель не совсем указатель - это скорее смещение относительно экземпляра класса и не имеет смысла без экземпляра класса. Однако ведь тебе не нужно вызывать метод без экземпляра класса, не так ли? Делаешь что-нибудь типа:
Это как идея. В реальности все схема будет слегка другая, но принцип тот же. Это сообщение отредактировал(а) Fantasist - 1.10.2003, 19:26 -------------------- Волны гасят ветер... |
||||
|
|||||
| mr.DUDA |
|
|||
|
3D-маньяк ![]() ![]() ![]() ![]() Профиль Группа: Экс. модератор Сообщений: 8244 Регистрация: 27.7.2003 Где: город-герой Минск Репутация: 25 Всего: 232 |
[/QUOTE]message_map[WM_MSG1]=&CMsgHandler::HandleMsg;[QUOTE]
Уверен, что можно получить указатель на нестатический компонент-функцию класса ? имхо, закавыка у Jcs именно со статическими членами класса - окна (не хочет он их использовать), а более никак не получить указатель на ф-цию / указатель на this внутри функции оконного класса. Последнее достижимо только с пом. GetWindowLong (как предложил RAN). -------------------- ![]() |
|||
|
||||
| Fantasist |
|
|||
|
Лентяй ![]() ![]() ![]() Профиль Группа: Участник Клуба Сообщений: 1517 Регистрация: 24.3.2002 Репутация: 4 Всего: 41 |
Именно. Указатель на член класса. Таковой указатель, как я уже упоминал, не имеет смысла без указателя на экземпляр класса. Он сам по себе не является указателем, а является, так сказать "смещением" к члену класса. А вот экземпляр класса мы и храним в WindowLong. Как я понял, проблема была в том, чтобы не делать switch в процедуре обработки окна, а делать динамический мэппинг сообщений к процедурам обработки. Вот примерно таким способом его можно и сделать. -------------------- Волны гасят ветер... |
|||
|
||||
| RAN |
|
|||
|
Опытный ![]() ![]() Профиль Группа: Экс. модератор Сообщений: 709 Регистрация: 14.3.2003 Где: Щёлково Моск.обл. Репутация: 5 Всего: 6 |
Jcs, давай по порядку:
Из твоего топика я понял, что ты хочешь объять необъятное. Тебе нужен универсальные механизм для создания карты сообщений. Причём функции могут быть как членами класса, так и обячными глобальными. Конечно, нет ничего невозможного, но это сложно. Моё предложение тогда такое: в CreateWindow последним параметром передавать либо указатель на экземпляр класса, либо NULL. А в обработчике сообщений анализировать это значение. Если оно NULL, то вызывать _cdecl, иначе _thiscall. Проблема заключается в том, как узнать адрес функции и в том, что если тебе нужно в одном и том же окне совмещать и thiscall и cdecl, то придётся при регистрации функции передавать уазатель на экземпляр класса или NULL. Фуф, ну и намудрил я. Например:
Как можно получить адрес функции - члена класса? class A { public: void func(); }; A::func ? Витруальную можно найти в vtable, но это тоже не хорошо. Потому что в каждом компиляторе этот механизм может реализовываться по своему. (то что в VC и Builder есть различия знаю точно. Сам проверял) |
|||
|
||||
| Jcs |
|
|||
|
Бывалый ![]() Профиль Группа: Участник Сообщений: 156 Регистрация: 1.10.2003 Репутация: нет Всего: нет |
Цена использования нестатических функций в карте сообщений выше, чем получаемые преимущества, поэтому обработчик конкретного мессаджа должен быть статическим. Карта сообщений сейчас являет собой динамически связанный список, хотя как мне кажется в том способе, который предложили fantasist и RAN поиск сообщений будет происходить бытсрее.
|
|||
|
||||
| RAN |
|
|||
|
Опытный ![]() ![]() Профиль Группа: Экс. модератор Сообщений: 709 Регистрация: 14.3.2003 Где: Щёлково Моск.обл. Репутация: 5 Всего: 6 |
Это почему? map - это тоже список. Если тебя интересует скорость, то надо выделить память typedef LRESULT (*MSG_PROC) (HWND , WPARAM ,LPARAM ); MSG_PROC* Map = new MSG_PROC[WM_USER]; Обнулить эту область памяти. И потом добавлять в массив функции обработки сообщений. Это будет самый быстрый map. LRESULT CALLBACK CWnd::Proc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { MSG_PROC msgproc = Map[uMsg]; return( msgproc ? *msgproc(hwnd, wParam, lParam) : DefWindowProc( hwnd, uMsg, wParam, lParam ) ); } |
|||
|
||||
| Fantasist |
|
||||
|
Лентяй ![]() ![]() ![]() Профиль Группа: Участник Клуба Сообщений: 1517 Регистрация: 24.3.2002 Репутация: 4 Всего: 41 |
map - это не список. Чаще всего это дерево, оптимизированное для быстрого поиска по ключу. Конечно, самый быстрый способ взятие значения по ключу целого типа - это хранить эти значения в массиве. Единственный недостаток - надо выделить память сразу под весь возможный диапазон ключей. Как алтернатива - hash_map почти то же самое, что массив, но ограниченный.
Я все выше уже написал. Внимательно посмотрите приведенный мною код. Это стардант С++. -------------------- Волны гасят ветер... |
||||
|
|||||
| RAN |
|
|||
|
Опытный ![]() ![]() Профиль Группа: Экс. модератор Сообщений: 709 Регистрация: 14.3.2003 Где: Щёлково Моск.обл. Репутация: 5 Всего: 6 |
Хорошо. А можно динамически получать адрес виртуальной функции? CMsgHandler obj; obj.HandleMsg - адрес функции? |
|||
|
||||
![]()
|
| Правила форума "С++:Общие вопросы" | |
|
|
Добро пожаловать!
Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, Earnest Daevaorn |
| 0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей) | |
| 0 Пользователей: | |
| « Предыдущая тема | C/C++: Общие вопросы | Следующая тема » |
|
|
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности Powered by Invision Power Board(R) 1.3 © 2003 IPS, Inc. |