Здравствуйте, Odi$$ey, Вы писали:
OE>winapi — ООП? хм..
На самом деле, в WinAPI действительно чётко прослеживается ООП-подход. ООП базируется на трёх китах — инкапсуляция, наследование и полиморфизм. Всё это в WinAPI есть.
Инкапсуляция
WinAPI инкапсулирует объекты с помощью хэндлов, причём эта инкапсуляция получается намного сильнее, чем в типичной программе на C++. Мы не только ничего не знаем о внутреннем устройстве объектов, которые скрываются за хэндлами, — мы не знаем также их размер и местоположение. Объекты, с которыми мы работаем на уровне WinAPI, очень тяжело "испортить", перезаписав их память, вызвав для них неправильный метод и т. п. По сути дела, единственный способ сделать что-либо с объектом — это использовать связанный с ним API, то есть его
интерфейс. Таким образом, в WinAPI очень чётко прослеживается разделение интерфейса (API) и реализации — это и есть инкапсуляция.
Наследование
В WinAPI наследование наиболее ярко проявляется в случае с оконной системой. Сравним два фрагмента.
1. Гипотетический оконный API на C++:
// Создаём класс окна для нашей программы...
class CMyWindow : public CDefWindow
{
virtual int HandleMessage(...)
{
// Обрабатываем сообщение.
return CDefWindow::HandleMessage(...);
}
};
CWindowFactory::RegisterClass(CLASS(CMyWindow));
// ...и объект этого класса.
CDefWindow *pWnd = CWindowFactory::Create(_T("CMyWindow"), ...);
2. WinAPI:
// Создаём класс окна для нашей программы...
LRESULT CALLBACK MyWindowProc(...)
{
// Обрабатываем сообщение.
return DefWindowProc(...);
}
WNDCLASS wc;
wc.lpfnWndProc = MyWindowProc;
wc.lpszClassName = _T("CMyWindow");
RegisterClass(&wc);
// ...и объект этого класса.
HWND hWnd = CreateWindow(_T("CMyWindow"), ...);
Как говорится, найдите 10 отличий. С точки зрения синтаксиса фрагменты, безусловно, различны. Но с точки зрения семантики разницы нет никакой.
В этой связи я не очень понимаю аргумент о том, что можно передать функции GetWindowText любой хэндл. Вот например:
HFONT hFont;
GetWindowText(hFont, ...); // ошибка
GetWindowText((HWND)hFont, ...); // всё ОК
CFont *pFont;
pFont->GetWindowText(...); // ошибка
((CWnd*)pFont)->GetWindowText(...); // всё ОК
Разница, опять же, только в синтаксисе.
Полиморфизм
Полиморфизм тоже удобно рассмотреть на примере окон. Опять обратимся к гипотетическому примеру.
1. Гипотетический оконный API на C++:
vector<CDefWindow *> arrChildWindows;
// Получаем список дочерних окон.
for(int i=0; i<arrChildWindows.size(); i++)
arrChildWindows[i]->EnableWindow(false);
2. WinAPI:
vector<HWND> arrChildWindows;
// Получаем список дочерних окон.
for(int i=0; i<arrChildWindows.size(); i++)
EnableWindow(arrChildWindows[i], FALSE);
И в том, и в другом случае меня не заботит, к какому классу относится каждое из дочерних окон. Я могу задизаблить их все, используя единый интерфейс. Это и есть полиморфизм в действии. Аналогичным образом полиморфизм работает, когда мы ждём на произвольном объекте ядра с помощью WaitForSingleObject или, например, работаем со стримом через ReadFile/WriteFile — вне зависимости от того, файл ли это, пайп или драйвер.
Или рассмотрим такой пример:
SelectObject(hDC, hGdiObject);
По сути дела, это ничто иное как мультиметод. HDC скрывает от нас конкретную разновидность контекста (экран, принтер, память), а HGDIOBJECT — конкретную разновидность графического объекта (перо, кисть, фонт и т. д.). Мультиметоды не поддерживаются напрямую ни в C, ни в C++. Что не мешает использовать их в WinAPI.
Помимо основных концепций ООП, в WinAPI можно проследить и кое-какие паттерны проектирования. Например, CreateFile и CreateWindow — это по сути дела фабрики объектов. FindFirstFile/FindNextFile реализуют итератор. Окно, содержащее дочерние окна, может выступать как композит или декоратор — и в том, и в другом случае мы работаем с родительским окном, не заботясь о структуре окон внутри него. И т. д.
Что характерно, внутренняя реализация WinAPI очень удобно делается на классах. Например, оконная подсистема в Windows CE именно так и написана. Поверх WinAPI тоже очень легко положить "объектную модель". Многие популярные библиотеки, включая MFC и ATL/WTL — по сути дела тонкие обёртки над WinAPI. Они обеспечивают синтаксические удобства (вроде уничтожения объекта в деструкторе), но объектная ориентированность итоговой программы — не их заслуга. И это не случайно.
Одним словом, нужно провести чёткую грань между
концепциями ООП и
синтаксисом, поддерживающим эти концепции. Конценции ООП работают в WinAPI в полный рост. Ну а синтаксис — он уж какой есть.