Udostępnij za pośrednictwem


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;

Zobacz też

Inne zasoby

Uwagi techniczne przez liczbę

Uwagi techniczne według kategorii