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.
Observação
A biblioteca Microsoft Foundation Classes (MFC) continua sendo suportada. No entanto, não estamos mais adicionando recursos ou atualizando a documentação.
Esta observação descreve como usar várias heranças (MI) com Microsoft Foundation Classes. 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 escrever uma biblioteca de classes.
Os subtópicos a seguir descrevem como o MI afeta o uso de expressões MFC comuns, bem como abrangem algumas das restrições do 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 de CRuntimeClass não dá suporte a informações de tipo de runtime do 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 e CObject::operator new, devem ter qualificadores de escopo para 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 classes derivadas de CObject. 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 operator new e operator delete 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 Dump é recomendado. O exemplo a seguir reimplementa os operadores new e delete e o método Dump:
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 a herdação CObject virtual resolveria o problema da ambiguidade da função, mas esse não é o caso. Como não há dados de membro em CObject, você não precisa de herança virtual para evitar múltiplas cópias de dados de membro da 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.
CObject::IsKindOf e digitação em tempo de execução
O mecanismo de digitação em tempo de execução com suporte do MFC em CObject usa 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 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 tipo em relação a CFrameWnd, 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 abaixo é um aplicativo autônomo que consiste em uma classe derivada de 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;