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;