Compartilhar via


TN016: Com herança múltipla C++ MFC

Esta nota descreve como usar herança múltipla (MI) com o Microsoft Foundation Classes.O uso de MI não é necessário com MFC.MI não é usado em quaisquer classes MFC e não é necessário escrever uma biblioteca de classes.

sistema autônomo seguintes subtópicos Descrever sistema autônomo MI afeta o uso de comuns MFC idiomas, bem sistema autônomo que abrange algumas restrições de MI.Algumas dessas restrições são restrições Geral de C++.Outros são impostos pela arquitetura do MFC.

No participante desta nota técnica, você encontrará um aplicativo MFC completo que usa MI.

CRuntimeClass

O persistência e mecanismos de criação de objeto dinâmico do MFC usam o CRuntimeClass estrutura de dados para identificar exclusivamente classes.MFC associa um essas estruturas de cada classe dinâmica e/ou serializável no seu aplicativo.Essas estruturas são inicializadas quando o aplicativo é iniciado usando um objeto estático especial do tipo AFX_CLASSINIT.

A implementação corrente de CRuntimeClass não oferece suporte a informações de tipo de tempo de execução de MI. Isso não significa que não é possível usar MI em seu aplicativo MFC.No entanto, você terá determinadas responsabilidades ao trabalhar com objetos que têm mais de uma classe base.

The CObject::IsKindOf método não corretamente determinará o tipo de um objeto se ele tiver várias classes base. Portanto, você não pode usar CObject sistema autônomo uma classe base virtual e todas sistema autônomo chamadas de CObject funções de membro, sistema autônomo CObject::Serialize e CObject::operador novo deve ter o escopo qualificadores, de modo que C++ pode disambiguate a telefonar de função apropriada. Quando um programa usa MI no MFC, a classe que contém o CObject classe base precisa ser a classe mais à esquerda da lista de classes base.

Uma alternativa é usar o dynamic_cast operador. Converter um objeto com MI para uma de suas classes base forçará o compilador a usar as funções na classe base fornecida.Para obter mais informações, consulte dynamic_cast do operador.

CObject - A raiz de todas as classes

Todas as classes significativas derivam direta ou indiretamente da classe CObject. CObject o não possui dados membro, mas tem algumas funcionalidades do padrão. Quando você usa MI, você normalmente será herdar de duas ou mais CObject-classes derivadas. O exemplo a seguir ilustra como uma classe pode herdar um CFrameWnd and a CObList:

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

Neste caso CObject Há duas vezes. Isso significa que você precisa uma maneira disambiguate qualquer referência a CObject métodos ou operadores. The operator new e Excluir operador são dois operadores que devem ser disambiguated.sistema autônomo outro exemplo, o código a seguir causará um erro em time de compilar:

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

Reimplementação CObject métodos

Ao criar uma nova classe que tem dois ou mais CObject derivadas de classes base, você deve reimplementar o CObject métodos que você deseja que outras pessoas para usar. Operadores new e delete são obrigatórias e Despejo é recomendado.O exemplo a seguir reimplements o new e delete operadores e o Dump método:

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

Herança virtual de CObject

Pode parecer que praticamente herdando CObject deve resolver o problema da função ambigüidade, mas que não é o caso. Porque não há nenhum dado de membro na CObject, herança de virtual para impedir que várias cópias de uma classe base de dados de membro não é necessário. No primeiro exemplo que foi mostrado anteriormente, a Dump método virtual é ainda ambíguo porque é implementado diferente no CFrameWnd e CObList. A melhor maneira para remover a ambigüidade é seguir as recomendações apresentadas na seção anterior.

CObject::IsKindOf e em time de execução digitação

O em time de execução digitando mecanismo suportado pelo MFC em CObject usa as macros DECLARE_DYNAMIC, IMPLEMENT_DYNAMIC, DECLARE_DYNCREATE, IMPLEMENT_DYNCREATE, DECLARE_SERIAL e IMPLEMENT_SERIAL. Essas macros podem executar um em time de execução digite verificação para garantir segurança downcasts.

Essas macros suportam apenas uma classe base e funcionarão de forma limitada para classes herdadas multiplicar.A classe base que você especificar no IMPLEMENT_DYNAMIC ou IMPLEMENT_SERIAL deve ser a classe base primeira (ou mais à esquerda). Esse posicionamento permitirá que você faça verificação de tipo para a classe base mais à esquerda só.O em time de execução sistema tipo saberá nada sobre classes de base adicionais.No exemplo a seguir, os sistemas de time de execução fará digite verificar CFrameWnd, mas será saber nada sobre CObList.

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

Mapas de mensagem e CWnd

MFC mensagem MAP para o sistema funcione corretamente, há dois requisitos adicionais:

  • Deve haver apenas um CWnd-classe base derivada.

  • The CWnd-classe base derivada deve ser a classe base primeira (ou mais à esquerda).

Aqui estão alguns exemplos que não funcionam:

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

Um programa de exemplo usando MI

O exemplo a seguir é um aplicativo autônomo que consiste em uma classe derivada de CFrameWnd e CWinApp.Não é recomendável que você estruturar um aplicativo dessa maneira, mas isso é um exemplo de aplicativo MFC menor que tem uma classe.

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

Consulte também

Outros recursos

Notas técnicas por número

Notas técnicas por categoria