Легалов А. И.
Шрифт:
В заключение отметим, что процедура диалога, общая для всех типов диалогов, реализована так, чтобы ответить на три вида сообщений: WM_INITDIALOG, WM_COMMAND и WM_NOTIFY. Фактически, все они направляют эти сообщения к объекту — контроллеру. Он получает указатель на полиморфный объект контроллера вызывая в начале метод фабрики MakeController.
Обратите внимание, что, из этой точки мы позволяем Windows, отследить указатель на контроллер. Мы сохраняем его как GWL_USERDATA — специальный длинный, который ассоциируется с каждым окном, в особенности с нашим диалогом, и доступен через его дескриптор окна.
Мы должны быть, хотя бы внимательными. Прежде всего мы должны освободить контроллер после того, как использовали его. Мы делаем это при обработке WM_DESTROY.
Во-вторых, Windows имеет неудачную идею (привычку) посылать сообщения WM_COMMAND и WM_NOTIFY перед WM_INITDIALOG и после WM_DESTROY. Что можно здесь сказать? Я бы побил менеджера, который ответствен за эти дела. Но раз это есть, мы должны защитить себя, проверяя, является ли ctrl ненулевым перед вызовом OnCommand и OnNotify.
Здесь представлена красота полиморфизма в действии. Объект фабрики создан клиентом, использующим шаблонный класс. Этот объект передается конструктору ModalDialog. ModalDialog передает его процедуре диалога как пустой указатель (дело в том, что он должен пройти через Windows). Процедура Диалога получает его внутри сообщения WM_INITDIALOG как LPARAM. После прохождения пищеварительного тракта Windows он должен быть восстановлен к своей первоначальной форме, переводом его обратно к указателю на CtrlFactory — в базовый класс всех фабрик контроллера.
Когда мы вызываем его виртуальный метод MakeController, мы вызываем метод, переопределенный в шаблонном классе ControllerFactory. Он создает новый объект для класса ActualCtrl, определенного клиентом. Но снова, он возвращает этот объект к нам замаскированный как обобщенный указатель на DlgController. Так всякий раз, когда мы вызываем любой из виртуальных методов ctrl, мы выполняем клиентские переопределения, определенные в классе ActualCtrl. Это лучшее проявление полиморфизма: Вы записываете код, используя обобщенные указатели, но когда код выполнен, он вызывается с очень специфическими указателями. Когда Вы вызываете методы через эти указатели, Вы выполняете специфические методы, обеспеченные клиентом вашего кода.
Вот, что случается с фабрикой объектов, чей фактический класс
Передается конструктору ModalDialog как | void* |
Передаётся от Windows к ModalDialogProcedure как | LPARAM |
Приведение в ModalDialogProcedure к | CtrlFactory* |
А вот, что случается с объектными данными, чьим фактическим классом является EditorData.