|
|
Регистрация Восстановить пароль |
Повторная активизация e-mail |
Регистрация | Задать вопрос |
Заплачу за решение |
Новые сообщения |
Сообщения за день |
Расширенный поиск |
Правила |
Всё прочитано |
|
|
Опции темы | Поиск в этой теме |
20.05.2016, 19:36 | #1 |
Регистрация: 20.05.2016
Сообщений: 8
|
GUI, WinAPI
Уважаемые пользователи!
Я решил написать себе свои собственные классы для GUI и начал с написания базового скелета основных классов, на основе которых будут создаваться уже сами контролы (кнопки, эдиты, прогрессбары и прочие) как известно есть сабклассинг и суперклассинг при суперклассинге создаётся свой класс со своей оконной процедурой при сабклассинге идёт подмена оконной процедуры существующего класса на свою в остальном принцип одинаковый, поэтому я решил написать 3 класса: class IWindow class ISuperclassWindow : public IWindow class ISubclassWindow : public IWindow IWindow - базовый класс содержащий в себе общий код для ISuperclassWindow и ISubclassWindow. Оба этих производных класса содержат уникальный код для суперклассинга и сабклассинга соответствующе. Для теста я написал себе пару простеньких классов class CWindow : public ISuperclassWindow class CCommonButton : public ISubclassWindow Код работает но есть ошибки, при разрушении окна и при удалении экземпляра класса. Подробнее в самом коде, в функции основного потока main() и в событии нажития на кнопку CCommonButton::OnCick(...) Прошу вас мне помочь, т.к. я могу понять где ошибся. Также хочу заметить, что это мой первый опыт написания классов с наследованием. Поэтому не исключено, что ошибка в неправильной модели наследования. исходник в виде вложения внизу и вот сам код (укоротил, т.к. не помещалось. Полностью в исходнике) Код:
Код:
Последний раз редактировалось Alex11223; 20.05.2016 в 20:10. |
20.05.2016, 19:45 | #2 | ||
Старожил
Регистрация: 12.01.2011
Сообщений: 19,500
|
Цитата:
https://en.wikipedia.org/wiki/Inheri...d_superclasses Цитата:
Ушел с форума, https://www.programmersforum.rocks, alex.pantec@gmail.com, https://github.com/AlexP11223
ЛС отключены Аларом. Последний раз редактировалось Alex11223; 20.05.2016 в 19:52. |
||
20.05.2016, 19:52 | #3 | |
Регистрация: 20.05.2016
Сообщений: 8
|
Цитата:
https://msdn.microsoft.com/en-us/lib...=vs.85%29.aspx |
|
20.05.2016, 20:02 | #4 | |
Старожил
Регистрация: 31.05.2010
Сообщений: 13,543
|
Цитата:
Пиши пьяным, редактируй трезвым.
Справочник по алгоритмам С++ Builder |
|
20.05.2016, 20:18 | #5 | |
Старожил
Регистрация: 12.01.2011
Сообщений: 19,500
|
А, да, там про винапи речь, а не про наследование классов.
Цитата:
Кстати, в С++ лучше инициализировать поля класса через Код:
Код:
И тут в main наверно можно обойтись без new/delete, просто Код:
Ушел с форума, https://www.programmersforum.rocks, alex.pantec@gmail.com, https://github.com/AlexP11223
ЛС отключены Аларом. Последний раз редактировалось Alex11223; 20.05.2016 в 20:42. |
|
21.05.2016, 00:26 | #6 | |
Регистрация: 20.05.2016
Сообщений: 8
|
Спасибо тебе Alex11223 за ответ
Цитата:
virtual LRESULT DefMessageHandler(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam) = 0; сделано это чтоб в обоих классах наследниках (ISuper- и ISubclassWindow) этот метод был в обязательном порядке имплементирован. DefMessageHandler - это враппер для стандартной оконной процедуры, которая обрабатывает сообщения, которые не обрабатываются в самом классе. Для обоих классов этот метод имеет одинаковое имя но "под капотом" разные функции: - для суперкласса это DefWindowProc - для сабкласса это CallWindowProc либо DefSubclassProc, в зависимости от реализации Спасибо, но учту это позже. Сейчас проблемы покруче, чем более правильная инициализация. Можно, но не всегда вариант. Я поясню почему. Допустим я написал свой ГУИ и всё зашибись работает. Когда я пишу проект, то объявляю указатели на экземпляры класса в качестве глобальных переменных. Я не привык расходовать ресурсы чужого компа (пусть даже там 20 гигов опреативки, ведь они не мои) и беру столько сколько нужно. Если я объявляю указатель на класс как глобальную переменную, то память занимаемая им это 8 или 4 байта. Если я объявлю CWindow win, то этот экземпляр класса будет постоянно отжирать память (не знаю сколько, но значительно больше чем размер указателя), пока программа не завершится. К тому же я бы хотел иметь возможность динамически создавать контролы и удалять их вместе с экземпляром класса когда в них нет необходимости Теперь, скажу что сделал. delete экземпляра класса я вызываю сразу после его создания перед запуском цикла закачки сообщений для дебага. По сути должно произойти следующее: 1. Окно создаётся методом Create и получает разные сообщения типа WM_CREATE, WM_NCCREATE и пр. 2. метод SetParent и Show тоже докидывают в очередь своих сообщений 3. Вызывается DestroyWindow и делает тоже самое. Цель: Окно должно правильно создаться и разрушиться + освобождение памяти занимаемое классом. Но у меня крашилось на delete приложение. я сделал деструкторы во всех классах начиная с базового IWindow не виртуальным и вызываю метод Destroy(); в деструкторе самого CWindow. программа не крашится но не понимаю почему не работает наследование, которое я представлял себе так: первым вызывается деструктор IWindow (выполняет ::DestroyWindow) вторым деструктор ISuperclassWindow (выполняет ::UnregisterClass) третьим и пока-что последним деструктор CWindow (в нём пока что пусто, но может что-то быть) 1. Так вот мой вопрос правильно ли я понимаю последовательность вызова деструкторов при наследовании как у меня? если да, то почему приложение крашиться с виртуальными деструкторами? 2. Почему при закрытии окна GetLastError в main() возвращает ERROR_INVALID_WINDOW_HANDLE ? Я всё ещё без понятия как отловить эту ошибку и откуда она. 3. И последнее. я добавил себе ещё один маленький класс - комбобокс для тетса динамичного разрушения и создания этого контрола, при нажатии на кнопку. Всё работает, но почему-то после разрушения конрол всё ещё виден, хоть и не работает. Это так должно быть? Ведь после разрушения я вызывал перерисовку через InvalidateRect Если да, то получается нужно сначала его прятать, а потом разрушать в общем вот немного правленый код: https://mega.nz/#!4wZlWZjK!67n5Fnhxm...6yVvSL3NWxgE2U прошу о дальнейшей помощи и подсказках! |
|
21.05.2016, 08:20 | #7 |
Старожил
Регистрация: 13.07.2012
Сообщений: 6,330
|
Деструкторы вызываются в обратном порядке - сначала наследники, потом родители.
Объекты в куче занимают *больше* памяти, чем объекты в стеке. Последний раз редактировалось waleri; 21.05.2016 в 08:22. |
21.05.2016, 10:31 | #8 |
Старожил
Регистрация: 31.05.2010
Сообщений: 13,543
|
Чтода, то да. Мало того. Поток остаётся открытым (как ни странноо) Закрыть его можно EOFF. Почему? А хрен его знает. Ляп от создателей компиля. Утечка памяти, из-за этой фигни и просходит.
Пиши пьяным, редактируй трезвым.
Справочник по алгоритмам С++ Builder |
21.05.2016, 10:49 | #9 |
Старожил
Регистрация: 12.01.2011
Сообщений: 19,500
|
Причем тут поток? Вы о чем?
Ушел с форума, https://www.programmersforum.rocks, alex.pantec@gmail.com, https://github.com/AlexP11223
ЛС отключены Аларом. |
21.05.2016, 16:21 | #10 |
Регистрация: 20.05.2016
Сообщений: 8
|
В общем я тут кое-что проверил.
Взял отсюда http://www.winprog.org/tutorial/simple_window.html простой как пробка пример создания окна без всяких классов и наследований, но дописал, чтоб main() возвращала return (int) GetLastError(); Результат - на выходе ERROR_INVALID_WINDOW_HANDLE Далее у себя попробовал такой простой тест: в цикле закачки сообщений при каждом сообщении распечатываю код сообщения и GetLastError() Код:
Код:
::CreateWindowExW(0, TOOLTIPS_CLASSW, L"radio 1", WS_VISIBLE, 0, 0, 500, 500, HWND_DESKTOP, 0, 0, 0); При закрытии через Alt+F4 тоже ERROR_INVALID_WINDOW_HANDLE, но уже на сообщении WM_SYSCOMMAND (оно и понятно, тк это не то окно, которое закрывается при нажаттии л. кнопки мыши в NC области) И наконец прочитал тут (тема называется "unresolved ERROR_INVALID_WINDOW_HANDLE at the end of program", как и моя проблема) http://www.masmforum.com/board/index...c=15448.0;wap2 следующее от пользователя Dogim - "My theory therefore is that the error message is by design - it looks like the system is testing to see if the window handle still exists." Вывод: ERROR_INVALID_WINDOW_HANDLE (по крайней мере на выходе поcле разрушения главного окна) это нормально. У меня теперь уже надеюсь последний вопрос: Как правильно организовать наследование деструкторов или их вызовы, чтоб разрушение происходило в ISubclassWindow и ISuperclassWindow и (?) IWindow? сейчас у меня метод Destroy() вызывается в деструкторе самого CWindow иначе программа крашится с сообщением 'pure virtual method called...' не знаю какой у тебя компилятор, я сижу на CLion + MinGW64. Компилер соответственно от gcc Последний раз редактировалось wowks; 21.05.2016 в 16:23. |
|
Похожие темы | ||||
Тема | Автор | Раздел | Ответов | Последнее сообщение |
Создание GUI на WinAPI | 8Observer8 | Win Api | 66 | 14.12.2012 17:32 |
Различие кода mfc и WinApi(mfc ручками набили, а WinApi автоматически с генерировался!! нужно явное отличие, не могу найти) | Артём1991 | Помощь студентам | 0 | 25.03.2012 17:13 |
C++ и GUI | Kn793 | Общие вопросы C/C++ | 4 | 26.07.2010 12:54 |
c++ и gui | jodam | Общие вопросы C/C++ | 7 | 18.05.2010 11:06 |
GUI и Си (?) | Дырдин | Общие вопросы C/C++ | 3 | 15.01.2010 20:39 |