Re[2]: winapi - ООП или нет
От: Alexander Shargin Россия RSDN.ru
Дата: 08.05.07 13:02
Оценка: 112 (17) +12
Здравствуйте, 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 в полный рост. Ну а синтаксис — он уж какой есть.
--
Я думал, ты огромный страшный Бажище,
А ты недоучка, крохотный Бажик...
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.