Цієї записці описується використання декількох успадкування (MI) з Microsoft Базисні класи.
Чому множинного наслідування?
Там s поточні дебати в c + + і об'єктно орієнтованого громади над значення MI. Visual c + + компілятор і розвитку навколишнього середовища повністю підтримує MI.
Бібліотеки класів MFC була розроблена, щоб вам не потрібно розуміти MI використання MFC. MI не використовується в будь-якому MFC класів. Ми виявили, що, MI не потрібно писати бібліотеки класів, ні вона необхідна для написання застосунків, що серйозні. Використовувати MI, або не може бути особистим рішенням, тому ми залишимо це рішення для вас.
Отже, ви хочете використовувати MI?
Якщо ви вже розуміють, як використовувати MI, зрозуміти продуктивність компроміси і потрібний MFC, цей technote скажуть вам те, що ви повинні зробити. Деякі з обмеження загального C++ обмежень, інші вводяться з MFC архітектура.
Нижче описано деякі технічні питання про вплив MI на використання загальних MFC ідіоми. Наприкінці цього технічне Примітка повний MFC додаток, що використовує MI входить, що може витягти і скомпілювати.
CRuntimeClass
Наполегливість і механізми створення динамічного об'єкта MFC використовувати CRuntimeClass структури даних для однозначної ідентифікації класів. MFC зв'язує однієї структури цього типу з кожного динамічних і/або серіалізованим клас у додатку. Ці структури є ініціалізувати на час запуску додатків за допомогою спеціальних статичний об'єкт типу AFX_CLASSINIT. Вам не потрібно самі в реалізації цієї інформації, як це може змінитися між MFC.
Виконання CRuntimeClass не підтримує кілька успадкування виконавчі файли типу інформації. Це не означає, не можна використовувати у програмі MFC MI, але якщо ви робите, ви будете мати певні обов'язки, під час роботи із об'єктами, що мають більше одного базового класу.
CObject::IsKindOf член функція буде не правильно визначити тип об'єкта має декілька базових класів. Таким чином, не можна використовувати CObject як віртуальний базового класу, і всі дзвінки на CObject член функції, такі як Serialize і оператор нові повинні мати сферу відбіркових, так що C++ можна disambiguate виклик відповідні функції. Якщо ви знайдете необхідності використовувати MI в рамках MFC, то ви повинні бути впевнені, щоб зробити клас, що містять CObject базовий клас базових класів, у списку, клас зліва.
Поради з використання і зловживання MI перегляньте додаткові стилі програмування C++ та ідіоми на James O. Coplien (Еддісон Уеслі, 1992).
CObject - корінь всіх класів
Як ви знаєте, всі значні класи отримати прямо або опосередковано з класу CObject. CObject не має будь-які члени дані, але є деякі функціональність. При використанні MI, це буде загальні успадковувати два або більше CObject-класи, наприклад, CFrameWnd і CObList , що отримані:
клас CListWnd: CFrameWnd державних, громадських CObList
{
...
};
CListWnd myListWnd
У цьому випадку CObject входить у два рази, що призводить до дві проблеми:
myListW&nd.Dump(afxDump);
nbsp; / / час помилка, CFrameWnd::Dump або CObList::Dump компілятора
Рекомендовані дії
Під час створення нового класу з двома або більше CObject , отриманих базових класів, заново реалізувати ці CObject членів, які ви очікуєте людям використовувати. Оператори новий і Видалення є обов'язковими, звалища рекомендується. Наприклад:
клас CListWnd: CFrameWnd державних, громадських CObList
{
готелю:
nbsp; порожнечі * оператор новий (size_t nSize)
{повернення CFrameWnd::operator new(nSize);}
недійсними оператор delete (void * p)
{CFrameWnd::operator delete(p)};
недійсними дамп (CDumpContent & dc)
{CFrameWnd::Dump(dc);
CObList::Dump(dc); }
...
}
Віртуальної спадковості CObject?
Ви можете запитати, "Якщо ви успадковують CObject практично, не всі проблеми двозначності піти?".
Навіть в ефективну модель об'єкта Microsoft віртуальної спадковості не є настільки ефективними, як-віртуальної спадковості (як множинного наслідування не є настільки ефективними, як спадкування в деяких випадках). Оскільки немає даних член в CObject, віртуальної спадковості не потрібно, щоб запобігти кілька копій даних базового класу, член.
Реальний відповідь немає, віртуальної спадковості не вирішить проблеми двозначності, показано вище. Наприклад: Віртуальний член функції Dump є ще неоднозначні (з CFrameWnd і CObList здійснювати її по-різному).
Тому ми рекомендуємо наступні дії, описані вище забезпечити усунення протиріч:
CObject::IsKindOf і під час введення тексту
Механізм вводу виконавчі, підтримується MFC у CObject використовує макроси DECLARE_DYNAMIC, IMPLEMENT_DYNAMIC, DECLARE_DYNCREATE, IMPLEMENT_DYNCREATE, DECLARE_SERIAL та IMPLEMENT_SERIAL. Ці дати можливість перевірити тип під час для безпечного ролях downs.
Ці макроси лише підтримки одного базовий клас і буде працювати в обмеженій формі для множення успадкованих класів. Базовий клас, вказати в IMPLEMENT_DYNAMIC або IMPLEMENT_SERIAL повинні бути першим (або зліва) базового класу. Наприклад,
клас CListWnd: CFrameWnd державних, громадських CObList
{
nbsp; DECLARE_DY&NAMIC(CListWnd)
...
};
IMPLEMENT_DYNAMIC (CListWnd, CFrameWnd)
Це дозволить вам перевірка типів для зліва базового класу тільки. Під час тип системи буде знати нічого про додаткові бази (CObList в даному випадку).
CWnd і повідомлення карти
Для того, щоб MFC повідомлення карта система працювати належним чином є два додаткові вимоги:
У наведеному вище прикладі CFrameWnd є бази перший клас.
Деякі приклади, які не будуть працювати:
клас CTwoWi&ndows: Громадська CFrameWnd, громадськості по кредиту
nbsp; { ... };
/ / Помилка: дві копії CWnd
клас CListEdit: Громадська CObList, громадськості по кредиту
{ ... };
/ / Помилка: по кредиту (походить від CWnd) має бути першим
Зразкова програма, за допомогою MI
Наступні приклади є окрему програму, яка складається з одного класу, отриманих від CFrameWnd і CWinApp. Таким чином, структурування застосунок не в Рекомендовані, але це приклад найменший MFC додатка з одного класу.
Можна скоротити наступні програми та скопіювати його на верхній частині HELLOAPP.CPP у зразку MFC Генеральний сингл наслідування HELLOAPP. Потім побудувати програми, як зазвичай.
#include <afxwin.h>
class CHelloAppAndFrame : public CFrameWnd, public CWinApp
{
public:
CHelloAppAndFrame()
{ }
// Necessary evil for MI disambiguity
void* operator new(size_t nSize)
{ return CFrameWnd::operator new(nSize); }
void operator delete(void* p)
{ CFrameWnd::operator delete(p); }
// Implementation
// CWinApp overrides
virtual BOOL InitInstance();
// CFrameWnd overrides
virtual void PostNcDestroy();
afx_msg void OnPaint();
DECLARE_MESSAGE_MAP()
};
BEGIN_MESSAGE_MAP(CHelloAppAndFrame, CFrameWnd)
ON_WM_PAINT()
END_MESSAGE_MAP()
// since the frame window is not allocated on the heap, we must
// override PostNCDestroy not to delete the frame object
void CHelloAppAndFrame::PostNcDestroy()
{
// do nothing (do not call base class)
}
void CHelloAppAndFrame::OnPaint()
{
CPaintDC dc(this);
CRect rect;
GetClientRect(rect);
CString s = "Hello, Windows!";
dc.SetTextAlign(TA_BASELINE | TA_CENTER);
dc.SetTextColor(::GetSysColor(COLOR_WINDOWTEXT));
dc.SetBkMode(TRANSPARENT);
dc.TextOut(rect.right / 2, rect.bottom / 2, s);
}
// Application initialization
BOOL CHelloAppAndFrame::InitInstance()
{
// first create the main frame
if (!CFrameWnd::Create(NULL, "Multiple Inheritance Sample",
WS_OVERLAPPEDWINDOW, rectDefault))
return FALSE;
// the application object is also a frame window
m_pMainWnd = this;
ShowWindow(m_nCmdShow);
return TRUE;
}
CHelloAppAndFrame theHelloAppAndFrame;
Технічні примітки за номером |nbsp; Технічні примітки за категоріями