Esta anotação descreve como usar Múltiplo herança (MI) com o Microsoft Foundation Classes.
Por que Múltiplo herança?
Há um debate em curso no C++ e comunidades e orientada sobre o valor de MI. Ambiente de desenvolvimento e compilador do Visual C++ totalmente oferece suporte a MI.
A biblioteca de classes do MFC foi projetada para que você não precisa entender MI usar MFC. MI não é usada em qualquer uma das classes MFC. Nós encontramos que MI não é necessário escrever uma biblioteca de classes, nem é necessário para escrever aplicativos sérios. Para usar MI ou não pode ser uma decisão pessoal, então vamos deixar essa decisão para você.
Então você quer usar MI?
Se você já entendeu como usar MI, compreender as compensações de desempenho e deseja usar MFC, esta technote irá dizer-lhe o que deve fazer. Algumas das restrições são restrições gerais de C++, outros são impostos pela arquitetura do MFC.
A seguir descreve algumas das questões técnicas como MI afetar o uso de expressões idiomáticas MFC comuns. No final da presente nota técnica um aplicativo MFC completo usando MI está incluído que você pode extrair e compilar.
CRuntimeClass
A persistência e mecanismos de criação do objeto dinâmico do MFC usam a estrutura de dados de CRuntimeClass para identificar classes. MFC associa uma estrutura deste tipo com cada classe dinâmica e/ou serializável no aplicativo. Essas estruturas são inicializadas na inicialização do aplicativo usando um objeto estático especial do tipo AFX_CLASSINIT. Você não precisa preocupar-se com a implementação desta informação, como é susceptível de alterar entre versões do MFC.
A implementação atual de CRuntimeClass não oferece suporte a informações de tipo de tempo de execução Múltiplo herança. Isso não significa que você não pode usar MI em seu aplicativo do MFC, mas se você fizer isso, você terá certas responsabilidades ao trabalhar com objetos que têm mais de uma classe base.
A função de membro CObject:: IsKindOf corretamente não determinará o tipo de um objeto se ele tiver Múltiplo classes de base. Portanto, você não pode usar CObject como uma classe base virtual e todas as chamadas para funções de membro CObject como Serialize e operador novo precisa ter qualificadores de escopo para que C++ pode disambiguate a chamada de função apropriada. Se você encontrar a necessidade de usar MI no MFC, então você deve ser certo fazer a classe que contém a classe base CObject classe extrema esquerda na lista de classes base.
Informações sobre os usos e abusos de MI, consulte Avançado C++ Programming estilos e expressões idiomáticas por James O. Coplien (Addison Wesley, 1992).
CObject - A raiz de todas as Classes
Como você sabe, todas as classes significativas derivam direta ou indiretamente da classe CObject. CObject não tem quaisquer dados de membro, mas tem alguma funcionalidade padrão. Ao usar MI, é comum para herdar de dois ou mais CObject-classes derivadas, por exemplo, um CFrameWnd e um CObList:
classe CListWnd: público CFrameWnd, público CObList
{
...
};
CListWnd myListWnd
Nesse maiúscminúsc CObject é incluído duas vezes, que leva a dois problemas:
myListW&nd.Dump(afxDump);
nbsp; / / compile erro em tempo, CFrameWnd::Dump ou CObList::Dump
Etapas recomendadas
Quando criar uma nova classe com dois ou mais CObject derivado classes de base, reimplementar os Estados-Membros CObject que você espera que as pessoas usem. Novos operadores e Excluir são obrigatórios, despejar é recomendado. Por exemplo:
classe CListWnd: público CFrameWnd, público CObList
{
público:
nbsp; void * operador novo (size_t nTamanho)
{retornar CFrameWnd::operator new(nSize);}
operador void delete (void p)
{CFrameWnd::operator delete(p);}
privatevoid Dump (CDumpContent & dc)
{CFrameWnd::Dump(dc);
CObList::Dump(dc); }
...
}
Herança virtual de CObject?
Você pode perguntar: "se você herdar CObject virtualmente, não todos os problemas de ambigüidade desaparecem?".
Mesmo o modelo de objeto Microsoft eficiente, herança virtual não é tão eficiente como herança não-virtual (assim como herança múltipla não é tão eficiente quanto a herança única em certos casos). Uma vez que não há dados membro no CObject, herança virtual não é necessária para impedir que várias cópias dos dados de membro da classe base.
A verdadeira resposta é não, herança virtual não vai resolver os problemas de ambigüidade ilustrados acima. Por exemplo: a função de membro virtual de despejo é ainda ambígua (pois CFrameWnd e CObList implementação-lo maneira diferente).
Portanto recomendamos seguindo as etapas acima para oferecem desambiguação:
CObject:: IsKindOf e tempo de execução digitando
O mecanismo de tempo de execução digitação suportado pelo MFC em CObject usa as macros DECLARE_DYNAMIC, IMPLEMENT_DYNAMIC, DECLARE_DYNCREATE, IMPLEMENT_DYNCREATE, DECLARE_SERIAL e IMPLEMENT_SERIAL. Estes dão a capacidade de fazer uma verificação de tipo de tempo de execução para permitir o elenco seguras-downs.
Essas macros só suportam uma única classe base e funcionarão de forma limitada para classes herdadas multiplicar. A classe base especificada no IMPLEMENT_DYNAMIC ou IMPLEMENT_SERIAL deve ser a classe base primeira (ou extrema esquerda). Por exemplo,
classe CListWnd: público CFrameWnd, público CObList
{
nbsp; DECLARE_DY&NAMIC(CListWnd)
...
};
IMPLEMENT_DYNAMIC (CListWnd, CFrameWnd)
Isso permitirá que você digitar verificando para a classe base de extrema esquerda só. O sistema de tempo de execução tipo vai saber nada sobre bases adicionais (CObList , neste caso).
CWnd e mapas de mensagem
Para que o sistema de mapa de mensagem do MFC funcione corretamente, existem dois requisitos adicionais:
No exemplo acima, CFrameWnd é a classe de primeira base.
Alguns exemplos que não vão funcionar:
classe CTwoWi&ndows: público CFrameWnd, CEdit pública
nbsp; { ... };
/ / erro: duas cópias do CWnd
Classe CListEdit: público CObList, CEdit pública
{ ... };
/ / erro: CEdit (derivado de CWnd) deve ser o primeiro
Um programa de exemplo usando MI
O exemplo a seguir é um aplicativo autônomo que consiste em uma classe derivada de CFrameWnd e CWinApp. Esta forma de estruturar um aplicativo não for um recomendado, mas este é um exemplo de aplicativo do MFC menor com uma classe.
Você pode cortar o seguinte programa e copiá-lo em cima de HELLOAPP.CPP no MFC geral exemplo single-herança HELLOAPP. Em seguida, compilar o programa como faria normalmente.
#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;
Técnico anotações por número |nbsp; &Notas técnicas por categoria