TN016: Używanie wielu C++ dziedziczenia z MFC
Uwaga Ta informacje dotyczące używania wielokrotne dziedziczenie (MI) w programie Microsoft Foundation Classes.Wykorzystanie MI nie jest wymagane z MFC.MI nie jest używany w jakichkolwiek klas MFC i nie jest wymagany do zapisu Biblioteka klas.
Następujące tematy podrzędne opisują, jak MI wpływa na stosowanie wspólnego MFC idiomy jak również obejmujące niektóre ograniczenia MI.Niektóre z tych ograniczeń są ogólne ograniczenia C++.Inne są nakładane przez architekturę MFC.
Na końcu tej uwagi techniczne można znaleźć pełną aplikacji MFC, która używa MI.
CRuntimeClass
Trwałość i mechanizmy tworzenia obiektu dynamicznego użytkowania MFC CRuntimeClass struktury danych do jednoznacznej identyfikacji klas.MFC kojarzy jednego z tych struktur każdej klasy dynamicznej lub możliwy do serializacji w aplikacji.Struktury te są inicjowane podczas uruchamiania aplikacji za pomocą obiektu statycznego specjalnego typu AFX_CLASSINIT.
Obecna implementacja CRuntimeClass nie obsługuje MI runtime typu informacji.Nie oznacza to, że MI nie można używać w aplikacji MFC.Można będzie jednak niektóre obowiązki podczas pracy z obiektami, które mają więcej niż jednej klasy podstawowej.
CObject::IsKindOf Metoda będzie ustala poprawnie typ obiektu, jeśli ma on wiele klas podstawowych.Dlatego nie można używać CObject jako wirtualnego klasy podstawowej, a wszystkie wywołania CObject Członkowskich funkcje takie jak CObject::Serialize i Nowy CObject::operator musi mieć zakres kwalifikatory, tak że C++ można disambiguate wywołanie odpowiedniej funkcji.Gdy program użyje MI w ramach MFC, klasa zawierający CObject klasy podstawowej musi być klasy lewego na liście klas bazowych.
Alternatywą jest użycie dynamic_cast operatora.Rzutowanie obiektu z MI do jednego z jej klas podstawowych wymusi kompilatora do funkcji w podanej klasy podstawowej.Aby uzyskać więcej informacji, zobacz Operator dynamic_cast.
CObject - katalog główny wszystkich klas
Wszystkie klasy znaczących pochodzić bezpośrednio lub pośrednio z klasy CObject.CObjectjest nie ma żadnych danych, ale ma pewne funkcje domyślne.Użycie MI będzie zazwyczaj dziedziczą z dwóch lub więcej CObject-klasy pochodne.Poniższy przykład ilustruje, jak klasy mogą dziedziczyć CFrameWnd i CObList:
class CListWnd : public CFrameWnd, public CObList
{
...
};
CListWnd myListWnd;
W tym przypadku CObject jest dołączone dwa razy.Oznacza to, że potrzebny jest sposób do disambiguate wszelkie odniesienia do CObject metod lub podmiotów gospodarczych.operator new i usunąć operator są dwa operatory, które muszą sobie.Inny przykład poniższy kod powoduje błąd w czasie kompilacji:
myListWnd.Dump(afxDump);
// compile time error, CFrameWnd::Dump or CObList::Dump ?
Metody CObject reimplementing
Podczas tworzenia nowej klasy ma dwa lub więcej CObject podstawowej klasy pochodne powinny przeprojektowywać CObject metod, które chcesz użyć innych osób.Operatorzy new i delete są obowiązkowe i zrzutu jest zalecane.Reimplements następujący przykład new i delete operatory i Dump metody:
class CListWnd : public CFrameWnd, public CObList
{
public:
void* operator new(size_t nSize)
{ return CFrameWnd::operator new(nSize); }
void operator delete(void* p)
{ CFrameWnd::operator delete(p); }
void Dump(CDumpContent& dc)
{ CFrameWnd::Dump(dc);
CObList::Dump(dc); }
...
};
Dziedziczenie wirtualnego CObject
Może się wydawać, że praktycznie dziedziczenie CObject może rozwiązać problem niejednoznaczności funkcji, ale który nie jest.Ponieważ nie ma żadnych danych w CObject, nie trzeba dziedziczenie wirtualny zapobiegające wielu kopii danych Członkowskie klasy podstawowej.W pierwszym przykładzie podaną wcześniej Dump metoda wirtualna jest nadal niejednoznaczne, ponieważ jest zaimplementowana inaczej w CFrameWnd i CObList.Najlepszym sposobem usunięcia niejednoznaczności jest przestrzeganie zaleceń przedstawionych w poprzedniej sekcji.
CObject::IsKindOf i wpisując Run-Time
The run-time typing mechanism supported by MFC in CObject uses the macros DECLARE_DYNAMIC, IMPLEMENT_DYNAMIC, DECLARE_DYNCREATE, IMPLEMENT_DYNCREATE, DECLARE_SERIAL and IMPLEMENT_SERIAL.Te makra można wykonywać wyboru typu run-time do zagwarantowania bezpiecznego downcasts.
Te makra obsługuje tylko jednej klasy bazowej i będzie działać w sposób ograniczony dla klasy mnożenie dziedziczone.Klasa podstawowa, określ w IMPLEMENT_DYNAMIC lub IMPLEMENT_SERIAL powinny być klasy bazowej pierwszego (lub lewego).To rozmieszczenie umożliwi kontrolę tylko klasy podstawowej lewego typu.System typów w czasie wykonywania, będzie wiadomo nic o dodatkowe klasy podstawowej.Wykonaj w poniższym przykładzie systemów czasu wpisz sprawdzanie przeciwko CFrameWnd, ale będzie nic nie wiedzą o CObList.
class CListWnd : public CFrameWnd, public CObList
{
DECLARE_DYNAMIC(CListWnd)
...
};
IMPLEMENT_DYNAMIC(CListWnd, CFrameWnd)
CWnd i mapy wiadomości
Mapa wiadomości MFC systemu działają prawidłowo istnieją dwa dodatkowe wymagania:
Musi istnieć tylko jeden CWnd-klasy podstawowej.
CWnd-Pochodna klasy podstawowej musi być pierwszym (lub lewego) klasy podstawowej.
Oto kilka przykładów, które nie będzie działać:
class CTwoWindows : public CFrameWnd, public CEdit
{ ... };
// error : two copies of CWnd
class CListEdit : public CObList, public CEdit
{ ... };
// error : CEdit (derived from CWnd) must be first
Przykładowy Program przy użyciu MI
Następujące próbki jest aplikacja składająca się z jednej klasy pochodne CFrameWnd i CWinApp.Nie zaleca że struktury aplikacji w ten sposób, ale jest to przykład najmniejszą aplikacji MFC, która ma jedną klasę.
#include <afxwin.h>
class CHelloAppAndFrame : public CFrameWnd, public CWinApp
{
public:
CHelloAppAndFrame()
{ }
// Necessary because of 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()
// because 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;