Jenter Алекс
Шрифт:
В функции EnumWindowsCallback мы сначала отсеиваем невидимые окна, и окна, имеющие владельца. Затем мы проверяем, не является ли данное окно окном рабочего стола. Здесь мы не уподобляемся разработчикам Windows NT Task Manager и используем имя класса окна для проверки. Наконец, мы отбрасываем окна с пустым заголовком.
После того, как мы определи, что данное окно представляет некоторое приложение, мы собираем информацию об окне, чтобы передать ее пользовательской функции. Сначала мы получаем заголовок окна с помощью хорошо известной функцииGetWindowText. Затем мы пытаемся получить иконку окна. Обратите внимание, мы используем функцию SendMessageTimeout с флагом SMTO_ABORTIFHUNG для посылки сообщения WM_GETICON. Это гарантирует, что наше приложение не зависнет, даже если приложение, которому принадлежит окно, перестало обрабатывать сообщения.
Когда все параметры определены, мы вызываем пользовательскую функцию. Пользовательская функция, в свою очередь, может распоряжаться этими данными по своему усмотрению. Например, в тестовом приложении Process Viewer, которое сопровождает эту статью, она добавляет очередной элемент в список приложений.
1. Q175030 HOWTO: Enumerate Applications in Win32, Microsoft Knowledge Base.
ФОРУМ RSDN – ИЗБРАННОЕ
Тема: ООП и наследование
Вопрос: Есть базовый класс, из ЕГО конструктора вызывается метод ЭТОГО же (базового) класса.
Так вот. Этот класс наследуют другие классы. НО! В их конструкторах нет вызова someFunction, – КОТОРАЯ ВИРТУАЛЬНАЯ, и по логике должна переназначаться классами, которые наследуют Cbase
Но при объявлении Csomefrombase : public Cbase, при объявлении объекта вызывается someFunction класса Cbase! Но нужно, чтобы вызывалась ТОЛЬКО Csomefrombase::someFunction!
Кто-нибудь подскажет, как решить данную проблему?
UtandrПредположим, всё работает по твоей логике. Угадай, что произойдёт вот в таком случае?
Из конструктора даже виртуальные методы вызываются в соостветствии со статическим (а не динамическим) типом класса. Т.е. при вызове метода 'foo' из конструктора класса 'A' всегда вызывается метод 'A::foo', независимо от того, переопределялся ли это метод в наследнике или нет. В этом есть смысл: в момент выполнения конструктора базового класса класс-наследник еще не сконструировался и попытки вызывать его методы ни к чему хорошему не приведут (см. пример от IT)
Андрей ТарасевичВсё правильно, но я бы хотел уточнить некоторые детали реализации. На самом деле функции вызываются как обычно, т.е. по всем правилам вызова виртуальных функций через VMT. Если бы даже конструктор и вызывал виртуальные функции по другому, то его можно было бы легко обмануть, вызвав из него любую функцию из которой уже вызвать виртуальную.
Всё гораздо проще. Указатель на VMT инициализируется, как известно, в самом начале работы конструктора, но ПОСЛЕ вызова конструктора базового класса. Поэтому, каждый конструктор устанавливает VMT на своём уровне и здесь его уже никак не обмануть. С деструкторами ситуация такая же, только в обратном порядке.
ITВсе это действительно детали реализации. В данном конкретном случае естественный порядок инициализации указателя на VMT как нельзя лучше способствует соблюдению спецификации языка. Создатели компиляторов знают об этой спецификации и, например, в MSVC++ виртуальные методы при прямом вызове их из конструктора вызываются статически, а не виртуально (т.е. в общем случае ты не прав, говоря, что "на самом деле функции вызываются как обычно"). А вот если попытаться сделать непрямой вызов виртуального метода (через метод-последник), то тут уже действительно срабатывает "правильное" значение указателя на VMT.
Андрей ТарасевичU>> Кто-нибудь подскажет, как решить данную проблему?
Разделить создание объекта и конструирование, например, ввести метод Init, вызываемый после конструктора.
В принципе, можно поступить поизящней – уложить подобные действия в шаблонную функцию, как например в ATL реализована CComObject::CreateInstance.
АТ>Из конструктора даже виртуальные методы вызываются в соостветствии со статическим (а не динамическим) типом класса. Т.е. при вызове метода 'foo' из конструктора класса 'A' всегда вызывается метод 'A::foo', независимо от того, переопределялся ли это метод в наследнике или нет. В этом есть смысл: в момент выполнения конструктора базового класса класс-наследник еще не сконструировался и попытки вызывать его методы ни к чему хорошему не приведут (см. пример от IT)
А кроме того – можно попасться на вызове чисто виртуального метода, когда указатель на него еще не установлен. Например – так:
При создании объекта класса D первым, как полагается, будет создан объект класса C. В его конструкторе будет вызван статический метод Init, который, в свою очередь, вызовет виртуальный InitExtra, и вылетит с ошибкой Pure virtual call или что-то вроде этого, поскольку в VMT класса C на месте InitExtra находится 0 (вернее – вызов обработчика аварийной ситуации), а VMT наследника еще не создан.
Геннадий Васильев