TN016: c + + 다중 상속을 사용 하 여 MFC와 함께

이 노트에서는 다중 상속 (MI) Microsoft Foundation 클래스와 함께 사용 하는 방법을 설명합니다。

왜 다중 상속?

내 집 값 c + + 및 객체 지향 커뮤니티에 지속적인 논쟁이 있다. Visual c + + 컴파일러와 개발 환경 미를 완벽 하 게 지원。

MFC 클래스 라이브러리 설계 되었습니다 MFC를 사용 하 여 마일을 이해할 필요는 없습니다. 미시건은 MFC 클래스에서 사용 되지 않습니다. 우리 미 클래스 라이브러리를 작성 하지 않아도 없으며 그것 심각한 응용 프로그램을 작성 하기 위한 필요한 것으로 나타났습니다. 미 사용 수 개인 결정, 그래서 우리는 당신에 게 그 결정을 두고。

그래서 당신이 사용 미?

미를 사용 하 여 성능 장단점을 이해 하 고 MFC를 사용 하는 방법을 이미 알고 있다면이 technote를 수행 해야 합니다 말할 것 이다. 제한 사항 중 일부는 일반적인 c + + 제한, 다른 MFC 아키텍처에 의해 부과 된다.

다음 일부의 미 일반적인 MFC 관용구의 사용에 미치는 영향의 기술적인 문제 설명 합니다. 마일을 사용 하 여 완전 한 MFC 응용 프로그램에 포함 되어 있는이 기술 노트의 끝에 추출 수 및 컴파일。

CRuntimeClass

끈기와 MFC의 동적 개체 생성 메커니즘 CRuntimeClass 데이터 구조를 사용 하 여 클래스를 고유 하 게 식별 합니다. MFC 응용 프로그램에서 각 동적 및/또는 serializable 클래스와 이러한 종류의 하나의 구조를 연결합니다. 이러한 구조는 AFX_CLASSINIT형식의 특별 한 정적 개체를 사용 하 여 응용 프로그램 시작 시 초기화 됩니다. 당신이 필요 걱정 하지 자신이 정보 구현으로 MFC의 버전 간에 변경 될 가능성이。

현재 구현의 CRuntimeClass 다중 상속 런타임 형식 정보를 지원 하지 않습니다. 이 뜻 미 MFC 응용 프로그램에서 사용할 수 없습니다 있지만 둘 이상의 기본 클래스 개체에서 작업할 때 특정 책임을가지고 것입니다 할 경우,。

CObject::IsKindOf 멤버 함수를 올바르게 확인 하지 개체의 형식을 여러 기본 클래스에 있는 경우. 따라서, CObject 가상 기본 클래스를 사용할 수 없습니다 그리고 모든 호출이 Serialize 및 새로운 연산자 와 같은 멤버 함수가 CObject 는 c + +에는 적절 한 함수 호출 명확히 구분 수 있도록 범위 한정자를 가져야 할 것 이다. MFC 내에서 미를 사용할 필요가 있으면 다음 해야 CObject 기본 클래스의 기본 클래스 목록에서 가장 왼쪽 클래스를 포함 하는 클래스를 만들 수。

미의 남용 및 사용에 대 한 조언, 고급 c + + 프로그래밍 스타일과 숙어 James O. Coplien (애디슨 웨슬리, 1992)를 참조 하십시오.

CObject-모든 클래스의 루트

알다시피, 모든 중요 한 클래스 CObject클래스에서 직접 또는 간접적으로 파생 됩니다. CObject 구성원 데이터는 없지만 몇 가지 기본 기능을 가지고지 않습니다. 마일을 사용 하는 경우 두 개 이상의 CObject에서 상속에 공통 될 것입니다-파생 클래스는 CFrameWnd 및 CObList:

cListWnd 클래스: 공용 CFrameWnd, 공공 CObList
{
 ...
};
CListWnd myListWnd

이 경우에 CObject 포함 되어 두 번, 두 문제에 이르게:

권장 되는 단계

파생 된 기본 클래스를 두 개 이상의 CObject 가진 새 클래스를 만드는 경우 사용 하는 사람들을 기대 그 CObject 멤버를 다시 구현. 새 연산자 및 삭제 는 필수, 수 덤프 하는 것이 좋습니다. 예를 들어:

cListWnd 클래스: 공용 CFrameWnd, 공공 CObList
{
공개:
 nbsp;? void * new 연산자 (size_t nSize)
 ?????? {반환 CFrameWnd::operator new(nSize);}
 ?? void 연산자 delete (void * p)
 ?????? {CFrameWnd::operator delete(p);}

void 덤프 (CDumpContent & dc)
 ?????? {CFrameWnd::Dump(dc);
 ???????? CObList::Dump(dc); }
 ??? ...
}

Cobject의 가상 상속?

요청할 수 있습니다 "사실상 Cobject를 상속 하는 경우 않을 모든 모호성 문제 떠나?"。

효율적인 Microsoft 개체 모델에도 가상 상속 (마찬가지로 다중 상속은 경우에 따라 단일 상속으로 효율적으로) 비 가상 상속으로 효율적입니다. 가상 상속 이후 CObject에 없는 구성원 데이터, 기본 클래스 멤버 데이터의 여러 복사본을 방지 하기 위해 필요 하지 않습니다.

진짜 대답은 아니, 가상 상속 위의 그림 모호성 문제가 해결 되지 것입니다. 예를 들면: 덤프 가상 멤버 함수는 여전히 모호 (이후 CFrameWnd 및 CObList 다르게 구현)。

따라서 좋습니다 위의 단계에 따라 명확성을 제공 하기 위해:

CObject::IsKindOf 및 런타임 입력

CObject 에서 MFC에 의해 지원 되는 런타임 입력 메커니즘 DECLARE_DYNAMIC, IMPLEMENT_DYNAMIC, DECLARE_DYNCREATE IMPLEMENT_DYNCREATE, DECLARE_SERIAL , IMPLEMENT_SERIAL매크로 사용 합니다. 이러한 안전 캐스트 다운스 수 있도록 런타임 형식 검사를 할 능력을 줄。

이러한 매크로만 단일 기본 클래스를 지원 하 고 곱하기 상속 된 클래스에 대 한 제한 된 방식으로 작동 합니다. IMPLEMENT_DYNAMIC 또는 IMPLEMENT_SERIAL 에서 지정 하는 기본 클래스에는 첫 번째 (가장 왼쪽) 기본 클래스 이어야 합니다. 예를 들어,

cListWnd 클래스: 공용 CFrameWnd, 공공 CObList
{
 nbsp;? DECLARE_DYNAMIC(CListWnd)
 ?? ...
};
IMPLEMENT_DYNAMIC (CListWnd, CFrameWnd)(&N)

것만으로 가장 왼쪽 기본 클래스에 대 한 검사를 입력 할 수 있습니다. 런타임 형식 시스템 추가 기지 (CObList 이 경우)에 대해 아무것도 알 것 이다。

CWnd 및 메시지 맵

MFC 메시지 맵 시스템 올바르게 작동 하도록 하기 위해서는, 거기에 두 개의 추가 요구 사항:

위의 예제에서 CFrameWnd 는 첫 번째 기본 클래스입니다.

작동 하지 않는 몇 가지 예:

cTwoWindows 클래스: 공용 CFrameWnd, 공공 CEdit
 nbsp;? { ... };
 ?????? / / 오류: Cwnd의 두 복사본

CListEdit 클래스: 공용 CObList, 공공 CEdit
 ?? { ... };
 ?????? / / 오류: CEdit (Cwnd에서 파생) 첫 번째 여야 합니다(&N).

마일을 사용 하 여 샘플 프로그램

다음 예제는 CFrameWnd CWinApp에서 파생 된 클래스의 구성 된 독립 실행형 응용 프로그램입니다. 이 방법으로 응용 프로그램을 구축 권장, 하지만 이건 하나의 클래스와 작은 MFC 응용 프로그램의 예。

다음 프로그램을 잘라내어 HELLOAPP 상단에 복사할 수 있습니다.단일 상속 MFC 일반 샘플에 CPP 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; 카테고리별 기술 노트(&N)

Index