Observação
O acesso a essa página exige autorização. Você pode tentar entrar ou alterar diretórios.
O acesso a essa página exige autorização. Você pode tentar alterar os diretórios.
Esta nota descreve como usar a MI (herança múltipla) com as Classes do Microsoft Foundation. O uso de MI não é necessário com o MFC. A MI não é usada em nenhuma classe MFC e não é necessária para gravar uma biblioteca de classes.
Os subtópicos a seguir descrevem como o MI afeta o uso de expressões MFC comuns, bem como abrange algumas das restrições de MI. Algumas dessas restrições são restrições gerais do C++. Outros são impostos pela arquitetura MFC.
Ao final desta nota técnica, você encontrará um aplicativo MFC completo que usa MI.
CRuntimeClass
Os mecanismos de persistência e criação dinâmica de objeto do MFC usam a estrutura de dados CRuntimeClass para identificar exclusivamente classes. O MFC associa uma dessas estruturas a cada classe dinâmica e/ou serializável em seu aplicativo. Essas estruturas são inicializadas quando o aplicativo começa usando um objeto estático especial do tipo AFX_CLASSINIT.
A implementação atual não dá suporte a informações de CRuntimeClass tipo de runtime de MI. Isso não significa que você não pode usar MI em seu aplicativo MFC. No entanto, você terá certas responsabilidades quando trabalhar com objetos com mais de uma classe base.
O método CObject::IsKindOf não determinará corretamente o tipo de um objeto se ele tiver várias classes base. Portanto, você não pode usar CObject como uma classe base virtual e todas as chamadas para funções membro, como CObject::Serialize e CObject::operator new, devem ter qualificadores de escopo para CObject que o C++ possa desambiguar a chamada de função apropriada. Quando um programa usa MI dentro do MFC, a classe que contém a CObject classe base precisa ser a classe mais à esquerda na lista de classes base.
Uma alternativa é usar o dynamic_cast operador. A conversão de um objeto com MI em 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 Operator.
CObject – A raiz de todas as classes
Todas as classes significativas derivam direta ou indiretamente da classe CObject.
CObject não tem dados de membro, mas tem alguma funcionalidade padrão. Ao usar o MI, você normalmente herdará de duas ou mais CObjectclasses derivadas. O exemplo a seguir ilustra como uma classe pode herdar de um CFrameWnd e um CObList:
class CListWnd : public CFrameWnd, public CObList
{
// ...
};
CListWnd myListWnd;
Nesse caso CObject , é incluído duas vezes. Isso significa que você precisa de uma maneira de desambiguar qualquer referência a CObject métodos ou operadores. O operador novo e a exclusão do operador são dois operadores que devem ser desambiguados. Como outro exemplo, o código a seguir causa um erro em tempo de compilação:
myListWnd.Dump(afxDump); // compile time error, CFrameWnd::Dump or CObList::Dump
Reimplementando métodos CObject
Ao criar uma nova classe que tenha duas ou mais CObject classes base derivadas, você deve reimplementar os CObject métodos que deseja que outras pessoas usem. Operadores new e delete são obrigatórios e o despejo é recomendado. O exemplo a seguir simplifica os operadores e delete os new 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 do CObject
Pode parecer que a herdação CObject virtual resolveria o problema da ambiguidade da função, mas esse não é o caso. Como não há dados CObjectde membro, você não precisa de herança virtual para impedir várias cópias de dados de membro de classe base. No primeiro exemplo mostrado anteriormente, o Dump método virtual ainda é ambíguo porque é implementado de forma diferente dentro CFrameWnd e CObList. A melhor maneira de remover a ambiguidade é seguir as recomendações apresentadas na seção anterior.
Digitação de CObject::IsKindOf e Run-Time
O mecanismo de digitação em tempo de execução com suporte do MFC usa CObject as macros DECLARE_DYNAMIC, IMPLEMENT_DYNAMIC, DECLARE_DYNCREATE, IMPLEMENT_DYNCREATE, DECLARE_SERIAL e IMPLEMENT_SERIAL. Essas macros podem executar uma verificação de tipo de tempo de execução para garantir downcasts seguros.
Essas macros dão suporte apenas a uma única classe base e funcionarão de forma limitada para multiplicar classes herdadas. A classe base especificada em IMPLEMENT_DYNAMIC ou IMPLEMENT_SERIAL deve ser a primeira (ou a mais à esquerda) classe base. Esse posicionamento permitirá que você faça a verificação de tipo somente para a classe base mais à esquerda. O sistema de tipo de tempo de execução não saberá nada sobre classes base adicionais. No exemplo a seguir, os sistemas de tempo de execução farão verificação de CFrameWndtipo, mas não saberão nada sobre CObList.
class CListWnd : public CFrameWnd, public CObList
{
DECLARE_DYNAMIC(CListWnd)
// ...
};
IMPLEMENT_DYNAMIC(CListWnd, CFrameWnd)
CWnd e Mapas de Mensagens
Para que o sistema de mapa de mensagens MFC funcione corretamente, há dois requisitos adicionais:
Deve haver apenas uma
CWndclasse base derivada.A
CWndclasse base derivada deve ser a primeira (ou a mais à esquerda).
Aqui estão alguns exemplos que não funcionarão:
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 CFrameWnd e CWinApp. Não recomendamos que você estruture um aplicativo dessa maneira, mas este é um exemplo do menor aplicativo MFC 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;