다음을 통해 공유


TN016: MFC C++ 다중 상속을 사용

이 참고가 다중 상속 (MI) Mfc를 사용 하는 방법에 설명 합니다.MI 사용 MFC로 필요 하지 않습니다.MI에서 MFC 클래스를 사용 하 고 클래스 라이브러리를 작성할 필요가 없습니다.

다음 하위 항목 MI 물론 일반적인 MFC 구문이 MI의 제한 중 일부를 다루는 사용에 미치는 영향에 대해 설명 합니다.이러한 제한 중 일부는 일반적인 C++ 제한입니다.다른 MFC 아키텍처에서 조건이 적용 됩니다.

이 기술 노트의 끝에 MI를 사용 하 여 전체 MFC 응용 프로그램을 찾을 수 있습니다.

개의 CRuntimeClass

지 속성 및 MFC 사용의 동적 개체 작성 메커니즘은 개의 CRuntimeClass 클래스를 고유 하 게 식별 하는 데이터 구조입니다.MFC 이러한 구조 중 하나가 각 동적 및/또는 serializable 클래스에서 응용 프로그램을 연결합니다.특별 한 형식의 정적 개체를 사용 하 여 응용 프로그램을 시작할 때 이러한 구조 초기화 됩니다 AFX_CLASSINIT.

현재 구현에서는 CRuntimeClass MI 런타임 형식 정보를 지원 하지 않습니다.이 MI MFC 응용 프로그램에서 사용할 수 없습니다 의미 하지는 않습니다.그러나 둘 이상의 기본 클래스 개체를 사용할 때 특정 책임을 해야 합니다.

CObject::IsKindOf 메서드는 정확 하 게 결정 하지 개체 유형을 여러 기본 클래스에 있으면.따라서에서는 사용할 수 없습니다 CObject 는 가상 기본 클래스와 모든 호출은 CObject 멤버 함수 같은 CObject::Serialize새 CObject::operator 적절 한 함수 호출 해당 C++를 명확 하 게 수 있도록 범위 한정자가 있어야 합니다.MI MFC 내에서 프로그램을 사용 하는 경우 클래스는 포함는 CObject 기본 클래스는 기본 클래스 목록에서 가장 왼쪽 클래스 여야 해야 합니다.

대신 사용 하는 것은 dynamic_cast 연산자입니다.MI 해당 기본 클래스 중 하나에 있는 개체를 캐스팅 컴파일러에 제공 된 기본 클래스의 함수를 사용 하 게 됩니다.자세한 내용은 dynamic_cast 연산자를 참조하십시오.

CObject-모든 클래스의 루트

클래스에서 모든 중요 한 클래스는 직접 또는 간접적으로 파생 CObject.CObject하지는 멤버 데이터를 없지만 일부 기본 기능이 반드시 필요 합니다.MI를 사용 하면 일반적으로 두 개 이상의에서 상속 하 여 됩니다 CObject-클래스를 파생 합니다.다음 예제는 클래스에서 상속할 수는 CFrameWndCObList:

class CListWnd : public CFrameWnd, public CObList
{
 ...
};
CListWnd myListWnd;

이 경우 CObject 두 번 포함 됩니다.이 의미 하는 방법에 대 한 참조를 명확 하 게 해야 하는 CObject 메서드나 연산자입니다.operator newdelete 연산자 명확히 할 수 있어야 하는 두 연산자입니다.다른 예를 들어, 다음 코드를 컴파일 타임에 오류 발생:

myListWnd.Dump(afxDump);
    // compile time error, CFrameWnd::Dump or CObList::Dump ?

CObject 메서드 인해야합니다.

두 개 이상을 포함 하는 새 클래스를 만들 CObject 기본 클래스에서 파생 된 다시 구현 해야는 CObject 메서드를 사용 하는 다른 사람이 원하는 합니다.연산자 new 및 delete 필수 및 덤프 것이 좋습니다.다음 예제에서는 reimplements의 new 및 delete 연산자 및 Dump 메서드:

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); }
     ...
};

Cobject의 가상 상속

해당 상속 거의 것 처럼 보일 수 있습니다 CObject 함수 모호성을 해결 하는 있지만 그렇지 않습니다.있기 때문에 데이터가 없는 멤버 CObject, 가상 상속을 사용 하는 기본 클래스 멤버 데이터의 여러 복사본을 방지할 필요가 없습니다.이전에 표시 된 첫 번째 예제에서는 Dump 에서 다르게 구현 되므로 가상 메서드 여전히 모호한입니다 CFrameWndCObList.모호성을 제거 하는 가장 좋은 방법은 이전 섹션에 나와 있는 권장 사항을 따라야 하는입니다.

CObject::IsKindOf 및 런타임 입력

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.이러한 매크로 안전 downcast를 보장 하는 런타임 형식 검사를 수행할 수 있습니다.

이러한 매크로 하나의 기본 클래스 에서만 지원 및 여러 번 상속 된 클래스에 대 한 제한 된 방식으로 작동 합니다.기본 클래스에서 지정한 IMPLEMENT_DYNAMIC 또는 IMPLEMENT_SERIAL 첫 번째 (가장 왼쪽) 기본 클래스로 사용 해야 합니다.이 배치 하면 가장 왼쪽 기본 클래스에만 검사 합니다. 입력 하지 수 있습니다.런타임 형식 시스템에 추가 되는 기본 클래스에 대 한 아무 것도 알 수 있습니다.다음 예제에서는 런타임 시스템 수행 하는 형식에 대해 검사 CFrameWnd, 하지만 아무 것도 알 수 CObList.

class CListWnd : public CFrameWnd, public CObList
{
    DECLARE_DYNAMIC(CListWnd)
    ...
};
IMPLEMENT_DYNAMIC(CListWnd, CFrameWnd)

CWnd 및 메시지 맵

MFC 메시지 맵 시스템에 대 한 제대로 작동 하는 두 개의 추가 요구 사항

  • 있어야 하나만 CWnd-기본 클래스에서 파생 됩니다.

  • CWnd에서 파생 된 기본 클래스는 기본 클래스의 첫 번째 (가장 왼쪽) 이어야 합니다.

작동 하지 않는 몇 가지 예는 다음과 같습니다.

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

MI을 사용 하 여 샘플 프로그램

다음 예제는 파생 클래스가 구성 된 독립 실행형 응용 프로그램입니다 CFrameWndCWinApp.이 방식으로 응용 프로그램 구조 이지만 하나의 클래스를 가진 작은 MFC 응용 프로그램의 예로는 권장 하지 않습니다.

#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;

참고 항목

기타 리소스

번호 기술 정보

범주별 기술 노트